【问题标题】:Rails 4: issues with strong parameters and passing dataRails 4:强参数和传递数据的问题
【发布时间】:2014-05-08 05:15:33
【问题描述】:

大家好。

首先,我是 Rails 的新手。 4 年前我在大学里做过一些事情,现在我决定重新开始。第 4 版发生了很多变化。

无论如何,我遇到了强参数的问题。这是我所拥有的:

我使用的是 Ruby 2.1、Rails 4.1。

我正在尝试为带有参数(id、team_a、team_b、arena、date、score_a、score_b)的曲棍球比赛创建表格。 team 是一张桌子(id, name), arena 是一张桌子(id, name)。

当我将参数从表单传递到控制器时,json 参数似乎还可以。但是,当它转换为 match_params 时,它会丢失其他表中参数的一些值。例如,我传递 arena_id: 12,但它显示 arena_id: 为空白。

我在这件事上花了超过 5 天的时间。任何帮助表示赞赏。

部分代码如下。如果您需要我提供更多信息,请告诉我...

迁移数据

class CreateMatches < ActiveRecord::Migration
  def change
    create_table :matches do |t|
      t.references :team_a,     default: 1 # unknown
      t.references :team_b,     default: 1 # unknown
      t.references :arena,    default: 1 # unknown
      t.datetime :date
      t.integer :score_a
      t.integer :score_b
      t.timestamps
    end
    add_index :matches, :team_a_id
    add_index :matches, :team_b_id
    add_index :matches, :arena_id
  end
end

class CreateTeams < ActiveRecord::Migration
  def change
    create_table :teams do |t|
      t.string :name, null: false
      t.timestamps
    end
  end
end

class CreateArena < ActiveRecord::Migration
  def change
    create_table :arena do |t|
      t.string :name, null: false
      t.timestamps
    end
  end
end

ma​​tch.rb(模型)

class Match < ActiveRecord::Base
  belongs_to :team_a, :class_name => 'Team'
  belongs_to :team_b, :class_name => 'Team'
  belongs_to :arena
end

team.rb(模型)

class Team < ActiveRecord::Base
  has_many :matches

  accepts_nested_attributes_for :matches
end

arena.rb(模型)

class Arena < ActiveRecord::Base
  has_many :matches

  accepts_nested_attributes_for :matches
end

ma​​tches_controller.rb

class MatchesController < ApplicationController
  before_action :set_match, only: [:show, :edit, :score, :update, :destroy]

  include ActionView::Helpers::DateHelper

  def index
    # some code
  end

  def show
    # some code
  end

  def new
    @match = Match.new
    @teams = Team.all.order("name ASC")
    @arenas = Arena.all.order("name ASC")
  end

  # GET /matches/1/edit
  def edit
    # some code
  end

  def create

    puts YAML::dump(match_params)  # Checking passed params. Output is bellow

    @match = Match.new(match_params)  

    respond_to do |format|
      if @match.save
        format.html { redirect_to @match, notice: 'Match was successfully created.' }
        format.json { render action: 'show', status: :created, location: @match }
      else
        format.html { render action: 'new' }
        format.json { render json: @match.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
  end

  def destroy
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_match
    @match = Match.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def match_params
    params.require(:match).permit(:date, :score_a, :score_b, team_a_id: [:id, :name], team_b_id: [:id, :name], arena_id: [:id, :name])
  end

  public
end

teams_controller.rb

class TeamsController < ApplicationController
  before_action :set_team, only: [:show, :edit, :update, :destroy]

  layout :false

  def index
    @teams = Team.all
  end

  def show
  end

  def new
    @team = Team.new
  end

  def edit
  end

  def create
    @team = Team.new(team_params)

    respond_to do |format|
      if @team.save
        format.json { render action: 'show', status: :created, location: @team }
        format.html { redirect_to @team, notice: 'Team was successfully created.' }
      else
        format.html { render action: 'new' }
        format.json { render json: @team.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @team.update(team_params)
        format.json { head :no_content }
        format.html { redirect_to @team, notice: 'Team was successfully updated.' }
      else
        format.html { render action: 'edit' }
        format.json { render json: @team.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @team.destroy
    respond_to do |format|
      format.html { redirect_to teams_url }
      format.json { head :no_content }
    end
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_team
    @team = Team.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def team_params
    params.require(:team).permit(:name)
  end
end

arenas_controller.rb

class ArenasController < ApplicationController
  before_action :set_arena, only: [:show, :edit, :update, :destroy]

  layout false

  def index
    @arena = Arena.all
  end

  def show
  end

  def new
    @arena = Arena.new
  end

  def edit
  end

  def create
    @arena = Arena.new(arena_params)

    respond_to do |format|
      if @arena.save
        format.json { render action: 'show', status: :created, location: @arena }
        format.html { redirect_to @arena, notice: 'Arena was successfully created.' }
      else
        format.html { render action: 'new' }
        format.json { render json: @arena.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @arena.update(arena_params)
        format.json { head :no_content }
        format.html { redirect_to @arena, notice: 'Arena was successfully updated.' }
      else
        format.html { render action: 'edit' }
        format.json { render json: @arena.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @arena.destroy
    respond_to do |format|
      format.html { redirect_to arenas_url }
      format.json { head :no_content }
    end
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_arena
    @arena = Arena.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def arena_params
    params.require(:arena).permit(:name)
  end
end

ma​​tches/_match.html.erb

<%= form_for(@match, html: {role: 'form', class: 'form-horizontal'}) do |f| %>
    <% if @match.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@match.errors.count, "error") %> prohibited this match from being saved:</h2>

          <ul>
            <% @match.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
            <% end %>
          </ul>
        </div>
    <% end %>

    <%= f.label 'Home Team' %>
    <%= f.collection_select :team_a_id, @teams, :id, :name, {prompt: true}, {class: ''} %>

    <%= f.label 'Visitor Team' %>
    <%= f.collection_select :team_b_id, @teams, :id, :name, {prompt: true}, {class: ''} %>

    <%= f.label 'Arena' %>
    <%= f.collection_select :arena_id, @arenas, :id, :name, {prompt: true}, {class: ''} %>

    <%= f.label 'Date' %>
    <%= f.datetime_select :date, class: 'form-control' %>

    <%= f.submit value: 'Submit' %>

 <% end %>

这是我在转储数据后在控制台中得到的内容:

Started POST "/matches" for 127.0.0.1 at 2014-05-06 18:24:20 -0700
Processing by MatchesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0RJjnpczVkp2unG9VITyHYC89ThgELn5kVE2wYRymBU=", "match"=>{"team_a_id"=>"24", "team_b_id"=>"27", "arena_id"=>"21", "date(1i)"=>"2014", "date(2i)"=>"5", "date(3i)"=>"6", "date(4i)"=>"18", "date(5i)"=>"24"}, "commit"=>"Update"}
User Load (0.5ms)  SELECT  `users`.* FROM `users`  WHERE `users`.`id` = 1  ORDER BY `users`.`id` ASC LIMIT 1
--- !ruby/hash:ActionController::Parameters
date(1i): '2014'
date(2i): '5'
date(3i): '6'
date(4i): '18'
date(5i): '24'
team_a_id:
team_b_id:
arena_id:
   (0.2ms)  BEGIN
  SQL (1.5ms)  INSERT INTO `matches` (`created_at`, `date`, `arena_id`, `team_a_id`, `team_b_id`, `updated_at`) VALUES ('2014-05-07 01:24:20', '2014-05-07 01:24:00', NULL, NULL, NULL, '2014-05-07 01:24:20')
   (0.2ms)  COMMIT
Redirected to http://localhost:3000/matches/90
Completed 302 Found in 13ms (ActiveRecord: 2.4ms)

【问题讨论】:

  • SP 悄悄地吃掉未经许可的参数。识别您可能希望在开发中允许的参数的一种快速方法是在 Rails 配置中设置 config.action_controller.action_on_unpermitted_parameters = :raise。它会抱怨合法但应该被忽略的参数,所以它实际上只是在需要时临时使用的东西。

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


【解决方案1】:

查看您的 match_params,并将其与从表单传递到控制器的参数进行比较。

def match_params
  params.require(:match).permit(:date, :score_a, :score_b, team_a_id: [:id, :name], team_b_id: [:id, :name], area_id: [:id, :name])
end

Parameters: {"utf8"=>"✓", "authenticity_token"=>"0RJjnpczVkp2unG9VITyHYC89ThgELn5kVE2wYRymBU=", "match"=>{"team_a_id"=>"24", "team_b_id"=>"27", "arena_id"=>"21", "date(1i)"=>"2014", "date(2i)"=>"5", "date(3i)"=>"6", "date(4i)"=>"18", "date(5i)"=>"24"}, "commit"=>"Update"}

您允许match_params 中的arena_id 作为一个名为area_id 的数组,其中包含元素:id 和:name。但是,它是从您的表单中以arena_id 传递的。您应该将 match_params 函数更改为:

def match_params
  params.require(:match).permit(:date, :score_a, :score_b, :team_a_id, :team_b_id, :arena_id)
end

请注意,我还更改了 :team_a_id 和 :team_b_id 以与您的参数中传递的内容保持一致,尽管看起来您传递的不是 :score_a 或 :score_b。您应该查看 Rails 指南中的 strong parameters 以了解更多信息。

【讨论】:

  • 感谢 JKen。从我的角度来看,它确实看起来很愚蠢。实际上我使用的名称是 Stadium(复数 Stadia),但在将代码粘贴到 stackoverflow 之前,我将其更改为 Arena 并拼错了。无论如何,问题都是一样的。在最初的表格中,我没有通过分数,因为我是在游戏结束后单独输入它们。
【解决方案2】:

好的,我发现了我的错误。 (感谢 JKen13579)

我把参数放错地方了。

应该是这样的:

def match_params
    params.require(:match).permit(:date, :score_a, :score_b, :team_a_id, :team_b_id , :arena_id)
end

def team_params
  params.require(:team).permit(:name, matches_params:[:id, :match_id, :name])
end

def arena_params
  params.require(:arena).permit(:name, matches_params:[:id, :match_id, :name])
end

它解决了这个问题。

【讨论】:

  • 我曾建议在我的回答中将其更改为 match_params。
  • 谢谢。我实际上是从你的建议开始的,然后一步一步地修改了整个事情。我可以看到我搞砸了。
  • 没问题。强参数肯定很棘手,需要一些时间来适应。
【解决方案3】:

当你调用这个时,除了名字之外的所有东西都会被删除:

params.require(:arena).permit(:name)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 2015-11-04
    • 2013-02-24
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多