Rails 6 - 允许 "dynamic" 散列参数

Rails 6 - permit "dynamic" hash params

此按钮当然会重定向到 form_for 创建新消息:

<%= link_to "Send message" , new_message_path( :message => { :user_id => @profile.user.id, :category => 1 } ) %>

但我看到了这个:

ActiveModel::ForbiddenAttributesError in MessagesController#new

def new

    @message_new = current_user.messages_send.new(params[:message])

end

在我的 Rails 4.0.0 中的旧脚本中它可以工作......我读了一些我尝试在 messages_controller

def message_params
  params.require(:message).permit(:some_params ... ,  :message => {})
end

但仍然没有任何改变。

如果有人会搜索答案:

def new

    @message_new = current_user.messages_send.new(message_params) /// not params[:message]

end

当然还有:

def message_params
  params.require(:message).permit(:some_params ... ,  :message => {})
end

一些意见。我不明白为什么您的代码允许在 message 参数的允许属性内使用 message 散列,这似乎是由于对允许参数的工作方式存在误解。示例:

class Message
  belongs_to :user

  validates :user, presence: true
  validates :category, presence: true

  # Let's say a Message has `user`, `category`, and `text` attributes
end

# Controller should look something more like this:
def new
  # Using message_params validates params' structure before using it to create an object
  @message = Message.new(message_params)
end

# Syntax: params.require(:object).permit(*permitted_attributes)
def message_params
  # This checks that params[:message].keys is a subset of [:user_id, :category, :text]
  params.require(:message).permit(:user_id, :category, :text)
end

# Permitted params should be structured like this example:
params: { 
  message: {
    user_id:  12,
    category: 1,
    text:     'Eat a plant!'
  }
}
# Note: `user_id`, `category`, and `text` are _permitted_ as params, 
# but their presence in the `message` hash is not required 
# (only the `message` key is required)

# Params like this will raise an error when using `message_params` 
# because `state` isn't defined as permitted in the `message_params` definition:
params: { 
  message: {
    user_id:  12,
    category: 1,
    text:     'Eat a plant!',
    state:    'initial'
  }
}
  • 您的初始代码只是调用 params[:message] 将消息的属性(例如 user_idcategorytext)传递给 Message 构造函数,而无需验证它们。
    • 这意味着您的初始代码会尝试使用您传递给它的 任何内容 创建对象(例如,当参数为 { message: { goblin: 'Spaghetti! } } 时,它会尝试创建对象如 Message.new(user_id: current_user.id, goblin: 'Spaghetti!')).
  • 当您切换到使用强参数时,您将切换到调用 message_params 方法
    • 此方法首先获取您的参数,这是一个 ActionController::Parameters 对象。
    • 然后调用参数对象的 require and permit 方法来验证参数不包含任何拼写错误或未定义为允许的附加键
    • 如果参数不遵循您在 message_params 中定义的允许结构,它会引发 ActiveModel::ForbiddenAttributesError 因为您试图向它传递一个不允许的属性。

建议:

  • 尝试在 Rails 控制台中使用允许的参数:
    rails console
    
    def validate_params(params_hash)
      params = ActionController::Parameters.new(params_hash)
      params.require(:message).permit(:user_id, :category, :text)
    end 
    
    good_params = {
      message: {
        user_id: 14,
        category: 1
      }
    }
    validate_params(good_params)
    => <ActionController::Parameters {"user_id"=>14, "category"=>1} permitted: true>
    validate_params(good_params.deep_merge(message: { text: 'Spaghetti!' }))
    => <ActionController::Parameters {"user_id"=>14, "category"=>1, "text"=>"Spaghetti!"} permitted: true>
    
    bad_params = good_params.deep_merge(message: { goblin: 'Spaghetti!' })
    => {:message=>{:user_id=>14, :category=>1, :goblin=>"Spaghetti!"}}
    validate_params(bad_params)
    Unpermitted parameter: :goblin # observe raised error
    => <ActionController::Parameters {"user_id"=>14, "category"=>1} permitted: true>
    
  • 尝试查看有关强参数的 RoR 指南:https://guides.rubyonrails.org/action_controller_overview.html#strong-parameters