Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

link_to / form_for doesn't work for singular resource #1769

Closed
Godisemo opened this issue Jun 19, 2011 · 67 comments
Closed

link_to / form_for doesn't work for singular resource #1769

Godisemo opened this issue Jun 19, 2011 · 67 comments
Assignees

Comments

@Godisemo
Copy link

In my routes I have

resource :company

and in my views

<% form_for(@store) do |f| %><% end %>

When

new action gets an error when rendering

undefined method hash_for_companies_path' for #Module:0x00000102bfd3f0`

The stack trace reviels that the problem occurs in

lib/action_dispatch/routing/polymorphic_routes.rb:133:in polymorphic_url'`

edit action can render without errors but the forms url is /company.4 where 4 is the id of the company.

This seems to be a bug that has been around for a very long time so I think it's time to fix it.

@pixeltrix
Copy link
Contributor

You're right the error has been around for a long while however a clean solution doesn't readily represent itself. The polymorphic_url helper has no 'intelligence' in how it operates - it has no information about what you've declared as resources in your routes.rb. All it has to go on it the name of the model and how that maps to the named url helpers.

In your case when passing a new Company instance it tries to map to the plural path as that's the standard route for the create action. The question is how to determine a singular resource from a regular resource - suggestions are welcome. The best solution I can think of is to try a respond_to? first and if it doesn't then try the singular option - I'll take a look at it.

@ghost ghost assigned pixeltrix Jun 19, 2011
@gucki
Copy link

gucki commented Jul 18, 2011

Ah, didn't know there's already a ticket for htis. So here's my post from the mailing list:

What about making the polymorphic routing in rails to try a plural route first. If it fails, try a singleton route. If it fails, raise.

This is not the nicest and most performant way (the result could be cached in production so it doesn't really matter in the end) but I guess it should solve most cases. Or is this too much magic?

@wildchild
Copy link
Contributor

I am wondering why this ticket pointed to 3.2 milestone?

@pixeltrix
Copy link
Contributor

Because it’s not a blocker for the 3.1 release and it may require too many changes to go into a patch release.

@mikeni
Copy link

mikeni commented Mar 9, 2012

i think this bug should be written in rails guides somewhere.

for anyone using a singular resource, they will eventually find themselves on this bug page. better to announce first

@maximeg
Copy link
Contributor

maximeg commented Mar 14, 2012

Still occurring.

@mikeni
Copy link

mikeni commented Mar 16, 2012

for now i just use scope =(

@phantomwhale
Copy link

Yep, my first time with the singular resource form, and I walked smack into this bug. Would be great to see a fix in an upcoming version - don't see any target milestone, so I presume it's not under active development at the moment ?

@kjakub
Copy link

kjakub commented Apr 14, 2012

Yep, here too, my first time with singular resource, lost 3h coz i was blaming myself like a first

@glebm
Copy link
Contributor

glebm commented May 3, 2012

+1

@felipero
Copy link
Contributor

felipero commented May 4, 2012

I believe respond_with has the same problem.

@pixeltrix
Copy link
Contributor

@felipero yes it will - as will anything where you can pass a model instance and get a url.

I haven't forgotten about this issue, it's just trickier than it seems to fix. The problem is there is no easy way to discern whether a model maps to a singular or a regular resource url. Checking for the presence of a collection url doesn't work as the resource may have been specified with :except => :index and trying to rescue route generation errors doesn't work because passing an instance to a singular resource url helper will generate a url with the format set to the id and no exception.

The only apparent way I can think of doing it is by creating a data structure that keeps a track of whether a set of routes is a singular resource and then querying that data structure in polymorphic_url. However before I or someone else can go ahead with that there needs to be a discussion whether we want the overhead of that structure.

@felipero
Copy link
Contributor

felipero commented May 4, 2012

Well, it is a non-blocking issue. Thanks for you prompt answer. :)

@zelig
Copy link

zelig commented Jun 16, 2012

I think someone ought to patch this. My thinking would not be along the lines of trying routes to fail (and fall back on the plural as in the comments in the rails issue) but go after association reflections.

Can we make the assumption that behind every nested resource form there is an activerecord association? No but we can test it

for form_for [a, b] (of classes A, B) if there is a model class A with has_many assoc to B, we can safely assume, expect that routes are set up to support a plural ("a_bs_path") for create. If there is a has_one we can safely assume, expect that routes are set up to support a singular ("a_bs_path"). If we find none, we fall back to the plural as the status quo educated guess. My 2 cents. Is this against modularity and decoupling MVC?

@pixeltrix
Copy link
Contributor

@zelig firstly, I think anything like that is tying your models to your routes too much. Secondly, what about non-AR models, and finally it doesn't fix the problem for top-level singular resources, e.g;

class Basket < ActiveRecord::Base
end

resource :basket

There's nothing in the model that's going to help with that - the only way it to store the fact that it's a singular resource and query that when generating the url. Adding metadata to the model won't help as a model may sometimes be a singular resource (/account) or a multiple resource (/admin/users/1).

@zelig
Copy link

zelig commented Jun 16, 2012

Surely this doesn't solve all problems but in the special case of nested AR resources, plurality can be reasonably guessed using model class associations, for others (i.e., top-level resource or non-AR models or models with implicit associations) the plural is a decent guess. This sounds to me a simple improvement but maybe the caveat is that it is not the right solution.

So where would you store resource singularity so that polyorphic_url could access this info? In case people are interested in fixing this ugly duckling.

@jakevose
Copy link

Add me to the list of people who just lost a bunch of time trying to figure out the "right" way to work around this and thinking myself crazy before stumbling upon this obscure reference to a long-standing, known bug.

@pjg
Copy link
Contributor

pjg commented Oct 17, 2012

Add me to the list of people who just lost a bunch of time trying to figure out the "right" way to work around this and thinking myself crazy before stumbling upon this obscure reference to a long-standing, known bug.

And me as well.

@pjg
Copy link
Contributor

pjg commented Oct 18, 2012

To anyone stumbling upon this issue, the workaround is quite simple. Given:

resource :billing_info

You generate the form_for call like this:

= form_for @billing_info, url: billing_info_path do |f|

@gmile
Copy link
Contributor

gmile commented Oct 18, 2012

@pjg one of the nice features of form_for is to generate a proper url, based on object's persistance state, i.e. autodetect a path with either _create or _update affixes. That said, i'm unsure if the solution you propose will handle both cases at the same time. Will it?

@pjg
Copy link
Contributor

pjg commented Oct 19, 2012

Yeah, it does handle both :create and :update actions.

@asymmetric
Copy link

It would be really nice to have this fixed, or at least to have the problem prominently documented somehow. Just spent 2hrs thinking it was an error on my end!

@jlbenc
Copy link

jlbenc commented Dec 17, 2012

Wasted 2+ hours hunting this issue down, :(

Thanks @pjg for your workaround! 👍

@gaurish
Copy link
Contributor

gaurish commented Dec 30, 2012

Today, I faced issue too. solved via workaround given Thanks @pjg 👍

@hasghari
Copy link

I agree with @mikeni that this bug should be documented in the Rails guides.

@nazar
Copy link

nazar commented Apr 2, 2013

Thanks @pijg for saving me an hour or three

@gustavokloh
Copy link

+1 for this issue!

And one more thanks @pjg

@philipgiuliani
Copy link

Why a bug like this isn't fixed yet?

@notrab
Copy link

notrab commented Aug 8, 2015

@philipgiuliani I'm sure you'll discover, judging by the comments above, there isn't any easy way to do this without polluting other classes within Rails for this behaviour.

The workaround is quite simple and to be honest, I don't see a problem. Throw it in the docs and just be done with it. Adding url: to the form declaration isn't so hard work for singular routes.

😴

@rails-bot
Copy link

This issue has been automatically marked as stale because it has not been commented on for at least
three months.

The resources of the Rails team are limited, and so we are asking for your help.

If you can still reproduce this error on the 4-2-stable, 4-1-stable branches or on master,
please reply with all of the information you have about it in order to keep the issue open.

Thank you for all your contributions.

maclover7 added a commit to maclover7/rails that referenced this issue Feb 7, 2016
maclover7 added a commit to maclover7/rails that referenced this issue Feb 7, 2016
A somewhat less invasive redo to rails#23535. The problem that makes rails#1769 so
hard to solve, is that `polymorphic_path` is only provided with an
database object, so this makes it hard to reinvent the routing tree.
This is the best solution I could come up with.
@rafaelfranca
Copy link
Member

See #17066 (comment)

@schuetzm
Copy link
Contributor

@rafaelfranca Care to explain why you closed this issue? The comment you referenced says it is still open "because it's a difficult problem to solve". Has it finally been fixed?

@rafaelfranca
Copy link
Member

Oops! Looks like I linked to the wrong comment. I could not find the comment that I explained that it is fine to use the :url option and that this problem is not something that we need to fix.

#23138 may fix this issue introducing a new API.

@matkoniecz
Copy link
Contributor

Why it is closed? #23138 is not merged and it is explicitly documented as existing bug in http://guides.rubyonrails.org/v4.1/routing.html

@azul
Copy link
Contributor

azul commented May 18, 2016

@matkoniecz - it's documented as you said including a workaround with the url param. And there is a bug that may fix this in the longer run. I think that is why it's closed. #23138 will track the progress on the fix now.

pixeltrix added a commit that referenced this issue Feb 20, 2017
Allow the use of `direct` to specify custom mappings for polymorphic_url, e.g:

  resource :basket
  direct(class: "Basket") { [:basket] }

This will then generate the following:

  >> link_to "Basket", @Basket
  => <a href="/basket">Basket</a>

More importantly it will generate the correct url when used with `form_for`.

Fixes #1769.
pixeltrix added a commit that referenced this issue Feb 21, 2017
Allow the use of `direct` to specify custom mappings for polymorphic_url, e.g:

  resource :basket
  direct(class: "Basket") { [:basket] }

This will then generate the following:

  >> link_to "Basket", @Basket
  => <a href="/basket">Basket</a>

More importantly it will generate the correct url when used with `form_for`.

Fixes #1769.
@IamNaN
Copy link
Contributor

IamNaN commented May 16, 2017

For anyone landing here via google, this is what got implemented: http://edgeguides.rubyonrails.org/routing.html#singular-resources

In short, add something like resolve('User') { [:user] } after you define the singular resource in routes.rb, where 'User' is the class name and :user is the resource name.

@tomrossi7
Copy link
Contributor

Couldn't this be fixed in the latest rails implementation by changing the behavior of form_with?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet