Rails 4:强参数和传递数据的问题

时间:2014-05-07 01:41:07

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

美好的一天,社区。

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

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

我使用的是Ruby 2.1,Rails 4.1。

我正在尝试使用参数(id,team_a,team_b,arena,date,score_a,score_b)为曲棍球比赛创建表单。团队是一个表(id,name),竞技场是一个表(id,name)。

当我将参数从表单传递给控制器​​时,json参数似乎没问题。但是,当它被转换为match_params时,它会丢失来自其他表的参数的一些值。例如,我传递了arena_id:12,但它显示了arena_id:as blank。

我花了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

match.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

matches_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

匹配/ _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)

3 个答案:

答案 0 :(得分:2)

查看您的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"}

您允许将arena_id match_params作为名为area_id的数组:id,其元素为:namearena_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或{{1}}。您应该在导轨指南中查看strong parameters以获取更多信息。

答案 1 :(得分:1)

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

我把params放在错误的地方。

应该是这样的:

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

解决了这个问题。

答案 2 :(得分:0)

除了名字之外的所有内容都会在您致电时删除:

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