1

Rails 4 には strong_parameters が付属しており、これは素晴らしい追加機能ですが、私はそれで問題に遭遇しました。私はポリモーフィックなモデルを持っていCommentますが、コントローラーが必要なパラメーターを受け入れることは一生できません。これが私のコードです(わかりやすくするために短縮されています):

ルート:

resources :articles do
  resources :comments
end

モデル:

class Article < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true
end

コントローラ:

class CommentsController < ApplicationController
  before_action :get_commentable

  def create
    @comment = @commentable.comments.new(comment_params)
    if @comment.save
      redirect_to @commentable, :notice => "Thank you!"
    else
      render :new
    end
  end

private

  def get_commentable
    resource, id = request.path.split("/")[1,2]
    @commentable = resource.singularize.classify.constantize.find(id)
    redirect_to :home unless defined?(@commentable)
  end

  def comment_params
    params.require(:comment).permit(:title, :message)
  end
end

投稿されたパラメーター (articles#show のフォームから):

{"authenticity_token"=>"v70nN8aFpofNw9vbVjhpsm9SwLOwKlOpNOEOTozUwCk=",
"comment"=>{"title"=>"Test","message"=>"Testing"},
"article_id"=>"1"}

私にはそれがうまくいくように見えますが、私が何をしようActiveModel::ForbiddenAttributesError in CommentsController#createとしても、私が試しても

  def comment_params
    params.permit! 
  end

コントローラーで。他の (非ポリモーフィック) モデルではそのような問題はありません。そのため、ポリモーフィズムと関係があると思われます。何か案は?

4

1 に答える 1

2

答えの欠如は、私がここで間違ったツリーを吠えていることを示しているように見えた. 問題は strong_parameters ではなく、役割とアクションに基づいた承認を行うために使用する CanCan gem にあります。どうやら、CanCan がパラメーターをオブジェクトに割り当てる方法 (CanCan がデフォルトの ActionController メソッドを引き継ぐ) に関係しているようです。このバグ レポートの詳細、特に"rewritten" からの返信を参照してください。つまり、これをアプリケーション コントローラーに配置すると、問題が解決します。

before_filter do
  resource = controller_name.singularize.to_sym
  method = "#{resource}_params"
  params[resource] &&= send(method) if respond_to?(method, true)
end

アップデート:

@scaryguy が指摘したように、上記のメソッドが関連付けられたモデルを持たないコントローラーから呼び出されると、フォールオーバーします。解決策は、単にメソッドに名前を付けて before_filter として呼び出すことですが、モデルを持たないコントローラーでは明示的に除外します (したがって、CanCan の自動アビリティ割り当ての恩恵を受けません)。私は次のように考えています。

before_filter :can_can_can

def can_can_can
  resource = controller_name.singularize.to_sym
  method = "#{resource}_params"
  params[resource] &&= send(method) if respond_to?(method, true)
end

次に、モデルレス コントローラーで次のようにします。

skip_before_filter :can_can_can
于 2013-05-15T05:00:58.530 に答える