强参数:不允许的参数:has_many_through 关系中的标签

Strong parameters: Unpermitted parameters: tags in has_many_through relation

我有几个models/controllers:

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)

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

Unpermitted parameters: tags

是的,我看过这个 post: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>)>

来自docs

Only permitted scalars pass the filter. ... passes params whose associated value is of type String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile or Rack::Test::UploadedFile. Otherwise, the key :name is filtered out.

在允许属性之前,您不能将标签数组元素转换为 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

感谢@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