form_for and scopes, rails 3

2019-01-26 11:06发布

问题:

I have a problem due to scopes and the form_for helper in rails 3. The routes - file looks like this:

scope "(/:tab)" do
  resources :article
end

The form looks something like this:

<%= form_for(@article) %>
   <%= f.label :title %>
   <%= f.text_field :title %>
    etc.
<%end%>

The tab - attribute is stored in params[:tab], as a string My problem is that this genereate wrong urls in the form. How could I get this to work ? The genreated url article_path(params[:tab], @article) works perfectly fine

回答1:

The answer I came up with was quite ugly, but works with both update and create:

<%= form_for(@article, :url => (@article.new_record? ? 
    articles_path(params[:tab]) : article_path(params[:tab], @article) do |f| %>

Update: A better solution would be to override the default_url_options-method to something like this:

def default_url_options(options={})
  { :tab => params[:tab] }
end

Then the <%= form_for @article do |f| %> could be used, and all urls are correctly generated



回答2:

Try:

<%= form_for [:tab, @article] do |f| %>
   <%= f.label :title %>
   <%= f.text_field :title %>
    etc.
<%end%>


回答3:

You could specify the path explicitly:

<%= form_for(@article, :url => article_path(@article, :tab => params[:tab]) %>


回答4:

I have found this to be a really irritating problem and have gotten around this for now with the following monkey patch. Generic like this, it's a little bid off as you're simply passing the entire bag of parameters to polymorphic_url which is what form_for uses under the hood to guess the route. A more concise approach would be to merge just the scope value.

My solution:

https://gist.github.com/1848467

module ActionDispatch
  module Routing
    module PolymorphicRoutes
      def polymorphic_path(record_or_hash_or_array, options = {})
        begin
            polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
        rescue Exception => e
            polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path).merge(params.reject{|k,v| ["controller", "action"].include? k.to_s}))
        end
      end
    end
  end
end


回答5:

In a very similar situation I defined the scope in routes like below:

scope :path => ":election_id", :as => "election" do 
  resources :questions
end

Now I have helpers like election_questions_path(@election)

In the forms I can use:

form_for [@election, @question] do |f|
  ...
end

In above examples @election is an instance of the Election model.

After integrating Friendly_id into this solution I got some pretty urls. For example "http://mydomain.com/elections-2012/questions/my-question"



回答6:

My solution of similar problem with form_for and scopes is to define new method in helpers/<model_name>/<model_name>_helper.rb, for example mine is sessions_helper.rb which contains

module Implant::SessionsHelper
  def sessions_form_path(session)
    session.new_record? ? sessions_path : session_path(session)
  end
end

And in my view I made

form_for(@session, url: sessions_form_path(@session)) do |f|

Problematic routes.rb part

scope module: 'implant' do
  resources :sessions
end

... and to get managed with :tab param you may add it to the helper method.