Forum: Ruby on Rails How do I force link_to/form helpers to use the superclass name in the path instead subclass?

Posted by Mohamad El-Husseini (Guest)
on 2012-08-07 18:14
(Received via mailing list)
I want my helpers to generate paths using a superclass instead of the
subclasses. Assuming I have Owner and Member that both inherit from 
User,
rails will use the current objects class name when generating paths:

Let's say current_user is a mod: <%= link_to current_user.name,
current_user %> will generate "/mod/:id". I want to force it to generate
"/user/:id" regardless of the subclass.

I can name the path:
<%= link_to current_user.name, user_path(current_user) %>

But I still want to use the convenience of just passing the object:
<%= link_to current_user.name, current_user %>

Is this possible?
Posted by Peter (Guest)
on 2012-08-08 16:45
(Received via mailing list)
On Tuesday, August 7, 2012 11:13:56 AM UTC-5, Mohamad El-Husseini wrote:
> <%= link_to current_user.name, user_path(current_user) %>
>
> But I still want to use the convenience of just passing the object:
> <%= link_to current_user.name, current_user %>
>
> Is this possible?
>
>
You didn't specify the rails version, but I'm pretty sure the answer is 
no.
 In Rails 2.3.14 your link to is eventually calling url_for, which calls
polymorphic_url (through polymorphic_path) since you're not passing it a
String, Hash or the symbol :back (
https://github.com/rails/rails/blob/v2.3.14/action...).
 In turn that eventually calls build_named_route_call, which uses
RecordIdentifier.plural_class_name(current_user), which is returning the
class name (
https://github.com/rails/rails/blob/v2.3.14/action...).
 And finally that in turn eventually calls current_user.model_name (
https://github.com/rails/rails/blob/v2.3.14/action...
)

You could look into overriding what model name returns for those 
classes,
but that seems really far reaching and dangerous.  I'd just use the path
helper since that best represents what you want to do, which is send an
Owner or Member object not to /owners/:id or /members/:id but to 
/users/:id
instead; ergo the verbosity doesn't seem bad to me, it helps clarify.

As an alternative, you could also define the /owners/:id and 
/members/:id
routes and point them at UsersController; not sure if that's okay to 
have
the extra routes, but that allows you to keep your shorthand notation, 
has
that map to the expected URL, but lets you DRY the underlying controller
class.

\Peter
Posted by Mohamad El-Husseini (Guest)
on 2012-08-08 20:51
(Received via mailing list)
I'm using Rails 3.2. And I'm pretty sure you can. Basically, to get a 
form
to post to the right model I need to set it up generically. My initial 
form
was:

= simple_form_for @user do |f|

To make it work I had to change it to this:

= simple_form_for :user, url: user_path(@user) do |f|

To work with link helpers, I added this as resource:

resources :owners, path: 'users', controller: 'users'
Posted by Dheeraj Kumar (Guest)
on 2012-08-08 21:05
(Received via mailing list)
It's simple. Use AR::Base#becomes


Dheeraj Kumar
Posted by Mohamad El-Husseini (Guest)
on 2012-08-08 21:09
(Received via mailing list)
Sorry, can you clarify your post a little? What does AR::Base#becomes
exactly mean? I'm relatively new to some of this stuff!
Posted by Dheeraj Kumar (Guest)
on 2012-08-08 21:22
(Received via mailing list)
http://api.rubyonrails.org/classes/ActiveRecord/Pe...

class User < Person
end

u = User.first
u.class.name #=> User

p = u.becomes(Person)
p.class.name #=> Person



Dheeraj Kumar
Posted by Dheeraj Kumar (Guest)
on 2012-08-08 21:24
(Received via mailing list)
AR is activerecord
AR::Base is what all active record models inherit from
a#b means i'm talking about method b in class a



Dheeraj Kumar
Posted by Mohamad El-Husseini (Guest)
on 2012-08-09 00:46
(Received via mailing list)
OK, thanks. But why would I do this instead of just adding the extra
resource?

resources :users
resources :owners, controller: 'users', path: 'users'

And in forms I could just call "form_for :user" instead of "form_for 
@user"?
Posted by Peter (Guest)
on 2012-08-09 17:02
(Received via mailing list)
On Wednesday, August 8, 2012 1:50:06 PM UTC-5, Mohamad El-Husseini 
wrote:
>
> To make it work I had to change it to this:
>
> = simple_form_for :user, url: user_path(@user) do |f|
>
>
I'm confused, i thought that is what you are trying to avoid?  I.e. you
don't want to have to specify user_path(@user), you wanted to just have
@user and have it compute the path helper as user_path, instead of
owner_path or member_path? In your solution you just put in user_path,
which makes your question moot, no?


> To work with link helpers, I added this as resource:
>
> resources :owners, path: 'users', controller: 'users'
>
>
Right, I didn't spell out the code like you did, but this is "As an
alternative, you could also define the /owners/:id and /members/:id 
routes
and point them at UsersController".  As a note, with that set of routes
defined you should be able to use your original form declaration:

= simple_form_for @user do |f|

 Because simple_form_for will eventually do url_for(@user) like link
helpers and therefore as long as owners and members are routed it should
work.

\Peter
Posted by Peter (Guest)
on 2012-08-09 17:09
(Received via mailing list)
On Wednesday, August 8, 2012 5:45:17 PM UTC-5, Mohamad El-Husseini 
wrote:
>
> OK, thanks. But why would I do this instead of just adding the extra
> resource?
>
> resources :users
> resources :owners, controller: 'users', path: 'users'
>

The reason would be if you didn't want to expose the urls:

/members/:id
/owners/:id

I.e. with those routes defined if @user is a member with ID 37 then:

link_to 'click here', @user             # => goes to '/members/37'
link_to 'click here', user_path(@user)  # => goes to '/users/37'

So if you just want to be able to do the first line and don't care about
the url, map the routes; if you want to exactly duplicate the second 
line
(i.e. your original code, and what would technically have 'helpers to
generate paths using a superclass instead of the subclasses') then you
could use becomes as such:

link_to 'click here', @user.becomes(User)    # => goes to '/users/37'

However, I personally think the one with user_path is more readable in 
this
case.

\Peter
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.