强参数:未允许的参数:has_many_through关系中的标记

时间:2015-01-20 16:04:03

标签: ruby ruby-on-rails-4 strong-parameters

我有几个型号/控制器:

event.rb:

class Event < ActiveRecord::Base
  belongs_to :category
  belongs_to :user
  has_many :event_tags
  has_many :tags, through: :event_tags
  has_many :event_skills
  has_many :skills, through: :event_skills

tag.rb

class Tag < ActiveRecord::Base
  has_many :events, through: :event_tags
  has_many :event_tags
end

event_tag.rb

class EventTag < ActiveRecord::Base
  belongs_to :event
  belongs_to :tag
end

user.rb:

class User < ActiveRecord::Base
  has_many :events # organized_events

events_controller.rb

class EventsController < ApplicationController
...

def create
    @event = Event.new(event_params)
    @event.user_id = current_user.id

    respond_to do |format|
      if @event.save
        format.html { redirect_to @event, notice: 'L\'évènement a été crée.' }
        format.json { render json: @event, status: :created, location: @event }
      else
        format.html { render action: "new" }
        format.json { render json: @event.errors, status: :unprocessable_entity }
      end
    end
  end

...

private
  def event_params
    params[:event][:date] = '%s %s' % [params[:event][:date].andand.split('/').reverse.join('-'),
                                       params[:event][:hour].andand.sub('h', ':')]
    params[:event].delete :hour
    params[:event][:tags] = params[:event][:tags].split(';').map { |t| Tag.where(name: t).first_or_create }
    params[:event][:skills] = params[:event][:skills].split(';').map { |s| Skill.where(name: s).first_or_create }
    binding.pry
    params.require(:event).permit(:user_id,
                                  :name,
                                  :date,
                                  :hour,
                                  :description,
                                  :picture,
                                  :category_id,
                                  {tags: []},
                                  {skills: []},
                                  :spots)

我的问题是,当我提交表单来创建活动时,我得到:

  

未经许可的参数:标签

是的,我看过这篇文章:Rails 4 Unpermitted Parameters for Array。我尝试添加:tags: []。但它似乎并不适用于我的情况。


调试信息:(在您看到的binding.pry断点处)

[4] pry(#<EventsController>)> params
=> {"utf8"=>"✓",
 "authenticity_token"=>"634lFWEsVDCD+yqPKBigmEJB0kRdHlLmyJpRwjTTVhU=",
 "event"=>
  {"name"=>"test tag 17",
   "category_id"=>"1",
   "date"=>" ",
   "tags"=>
    [#<Tag id: 3, name: "beer", created_at: "2014-12-05 11:21:27", updated_at: "2014-12-05 11:21:27">,
     #<Tag id: 4, name: "vodka", created_at: "2014-12-05 11:21:27", updated_at: "2014-12-05 11:21:27">,
     #<Tag id: 5, name: "champain", created_at: "2014-12-05 11:21:27", updated_at: "2014-12-05 11:21:27">],
   "skills"=>[],
   "spots"=>"",
   "description"=>"sdfsf"},
 "action"=>"create",
 "controller"=>"events"}
[5] pry(#<EventsController>)> event_params
Unpermitted parameters: tags
=> {"name"=>"test tag 17", "date"=>" ", "description"=>"sdfsf", "category_id"=>"1", "skills"=>[], "spots"=>""}
[6] pry(#<EventsController>)>
  • 如何正确地允许:tags param?
  • 我应该以不同的方式处理标签的提交(例如:event_params方法是使用拆分进行解析的正确位置吗?)

2 个答案:

答案 0 :(得分:2)

来自docs

  

仅允许的标量通过过滤器。 ...传递params,其关联值的类型为String,Symbol,NilClass,Numeric,TrueClass,FalseClass,Date,Time,DateTime,StringIO,IO,ActionDispatch :: Http :: UploadedFile或Rack :: Test :: UploadedFile。否则,密钥:名称将被过滤掉。

在允许属性之前,无法将标记数组元素转换为AR对象。你首先需要允许参数,然后你可以用对象改变它。

<强>更新 查看railscasts您可以看到模型,有一个方法:tagged_with

你可以创建:

class Event < ActiveRecord::Base
  def tagged_with(*tag_names)
    # create (or build) your tags
  end
end

在您的控制器中,您有event_paramstag_paramsskill_params

def create
  @event = Event.new(event_params)
  @event.tagged_with(tag_params)
  # Same thing with skills
  @event.user_id = current_user.id
  ...
end

...

def tag_params
  params.require(:event).permit(tags: [])
end

答案 1 :(得分:1)

感谢@Magnuss指出了这个问题。 (我不能允许AR类型的对象。)

我最终将我的控制器更改为:(现在它工作正常)

class EventsController < ApplicationController
  ...

  def create
    # added parse_event_params here. Also added in update method, not shown here.
    @event = Event.new(parse_event_params event_params)
    @event.user_id = current_user.id

    respond_to do |format|
      if @event.save
        format.html { redirect_to @event, notice: 'L\'évènement a été crée.' }
        format.json { render json: @event, status: :created, location: @event }
      else
        format.html { render action: "new" }
        format.json { render json: @event.errors, status: :unprocessable_entity }
      end
    end
  end

private
  # added this method
  def parse_event_params(event_params)
    event_params[:date] = '%s %s' % [event_params[:date].andand.split('/').reverse.join('-'),
                                     event_params[:hour].andand.sub('h', ':')]
    event_params.delete :hour
    event_params[:tags] = event_params[:tags].split(';').map { |t| Tag.where(name: t).first_or_create }
    event_params[:skills] = event_params[:skills].split(';').map { |s| Skill.where(name: s).first_or_create }
    event_params
  end

  # changed this method so it's only doing require/permit
  def event_params
    params.require(:event).permit(:user_id,
                                  :name,
                                  :date,
                                  :hour,
                                  :description,
                                  :picture,
                                  :category_id,
                                  :tags,
                                  :skills,
                                  :spots)

  end