Ruby on Rails - 保存一个模型相对于另一个模型的表单数据

时间:2015-08-22 01:33:20

标签: ruby-on-rails forms ruby-on-rails-3

我再次修改了这个问题以包含控制器文件。

在我们的应用中,我们有三种型号。用户模型,记分牌模型,团队模型。用户has_many记分板和记分板属于用户。记分板控制器中与两者相关联的创建操作的代码是" @scoreboard = current_user.scoreboards.build"。这段代码非常好用。

现在,问题出现在第三个模型上。记分牌模型拥有多个团队,每个团队都属于一个记分牌。这是一个has_many,belongs_to的关系。因此,外键位于team表中。记分板和团队迁移和模型文件分别在下面给出。

记分牌模型

class Scoreboard < ActiveRecord::Base
  belongs_to :user
  has_many :teams, dependent: :destroy
  default_scope -> { order(created_at: :desc) }
end

记分牌迁移

class CreateScoreboards < ActiveRecord::Migration
  def change
    create_table :scoreboards do |t|
      t.string :name_of_scoreboard
      t.string :name_of_organization
      t.string :name_of_activity
      t.references :user, index: true

      t.timestamps null: false
    end
    add_foreign_key :scoreboards, :users
    add_index :scoreboards, [:user_id, :created_at]
  end
end

团队模型

class Team < ActiveRecord::Base
  belongs_to :scoreboard
end

团队迁移

class CreateTeams < ActiveRecord::Migration
  def change
    create_table :teams do |t|
      t.string :name
      t.integer :win
      t.integer :loss
      t.integer :tie
      t.references :scoreboard, index:true

      t.timestamps null: false
    end
    add_foreign_key :teams, :scoreboards
  end
end

我认为我已正确关联模型。因此,我的团队控制器中用于创建操作的代码应该正确创建关联。控制器如下:

记分牌控制器:

class ScoreboardsController < ApplicationController

 before_action :logged_in_user, only: [:new, :create, :show, :index]
 before_action :correct_user, only: [:destroy, :edit, :update]

 def new
   @scoreboard = Scoreboard.new
 end

 def create
  @scoreboard = current_user.scoreboards.build(scoreboard_params)
  if @scoreboard.save
   flash[:scoreboard] = "Scoreboard created successfully"
   redirect_to scoreboard_path(@scoreboard)
  else
   render 'new'
  end
 end

 def show
  @scoreboard = Scoreboard.find_by_id(params[:id])
 end

  def index
    if params[:search]
      @scoreboards = Scoreboard.all.search(params[:search])
    else
      @scoreboards = current_user.scoreboards
    end
  end

 def edit
  @scoreboard = Scoreboard.find_by_id(params[:id])
 end

 def update
  @scoreboard = Scoreboard.find_by_id(params[:id])
  if @scoreboard.update_attributes(scoreboard_params)
   flash[:success] = "Updated Successfully"
   redirect_to scoreboard_path(@scoreboard)
  else
   render 'edit'
  end
 end

 def destroy
  @scoreboard = Scoreboard.find_by_id(params[:id])
  @scoreboard.destroy
  flash[:success] = "Deleted Successfully."
  redirect_to scoreboards_path
 end

private

  def scoreboard_params
   params.require(:scoreboard).permit(:name_of_scoreboard, :name_of_organization, 
                  :name_of_activity, :starts_at, :ends_at, :cities, :states, :country, :picture ) 
  end

   def correct_user
     @user = Scoreboard.find(params[:id]).user
     redirect_to scoreboards_path unless current_user?(@user)
   end

end 

这是球队的控制者:

class TeamsController&lt; ApplicationController中

def new
    @team = Team.new
  end

  def create
    @scoreboard= current_user.scoreboards.build
    @team = @scoreboards.teams.build(team_params)
    if @team.save
      flash[:success] = "Saved Successfully"
      redirect_to scoreboard_path
    else
      render 'new'
    end
  end

  def index

  end

  def show

  end

  private

  def team_params
    params.require(:team).permit(:name, :win, :loss, :tie)
  end

end

然而,我得到一个错误&#34;未定义的方法`团队&#39;为零:NilClass&#34;当我提交应用创建动作的表单时。我不确定为什么会这样,因为我对用户和记分板模型做了同样的事情。

2 个答案:

答案 0 :(得分:0)

我在回答你的问题后修正了我的答案:

我认为您的关联是正确的,也许可以尝试使用@scoreboard而不是记分牌。这样的事可能呢?

def blah
    .... some code ....
    @scoreboard = current_user.scoreboards.build
    @team = @scoreboard.teams.build
    .... more code ....
end

答案 1 :(得分:0)

Rails有很多方法可以通过用户输入创建相关记录。在这种情况下,我们假设您只想在记分板的上下文中创建团队。

我们要做的第一件事就是将球队路线嵌入记分牌:

# config/routes.rb
Rails.application.routes.draw do
  # ...
  resources :scoreboards do
    resources :teams, shallow: true
  end
end

这将为我们提供创建嵌套团队的路线:

             Prefix Verb   URI Pattern                                     Controller#Action
   scoreboard_teams GET    /scoreboards/:scoreboard_id/teams(.:format)     teams#index
                    POST   /scoreboards/:scoreboard_id/teams(.:format)     teams#create
new_scoreboard_team GET    /scoreboards/:scoreboard_id/teams/new(.:format) teams#new
          edit_team GET    /teams/:id/edit(.:format)                       teams#edit
               team GET    /teams/:id(.:format)                            teams#show
                    PATCH  /teams/:id(.:format)                            teams#update
                    PUT    /teams/:id(.:format)                            teams#update
                    DELETE /teams/:id(.:format)                            teams#destroy

为什么?,因为这提供了RESTful设计,很明显您正在创建嵌套资源。嵌套索引路径实际上是可选的。

如果您想要一个非嵌套索引,无论记分牌如何都显示所有团队,您可以按以下方式定义路线:

# config/routes.rb
Rails.application.routes.draw do
  # ...
  resources :teams, only: :index
  resources :scoreboards do
    resources :teams, shallow: true, except: :index
  end
end

如您所知,我们想要在Team

中构建Scoreboards#show个实例
# GET /scoreboards/1
def show
  @team = @scoreboard.teams.build
end

我们还需要在记分板中添加一个团队表单。让我们使用可重用的部分:

# app/views/scoreboards/show.html.erb 
<%= render partial: 'teams/form' %>
# app/views/teams/_form.html.erb
<%= form_for(@team.new_record? ? [@scoreboard, @team] : @team ) do |f| %>
  <% if @team.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@team.errors.count, "error") %> prohibited this team from being saved:</h2>

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

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :wins %><br>
    <%= f.number_field :wins %>
  </div>
  <div class="field">
    <%= f.label :loss %><br>
    <%= f.number_field :loss %>
  </div>
  <div class="field">
    <%= f.label :tie %><br>
    <%= f.number_field :tie %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

注意@team.new_record? ? [@scoreboard, @team] : @team。我们使用三元运算符(紧凑的if语句),以便表单正确路由新记录和编辑记录。

因此,在我们的TeamsController中,我们要设置回调以从params[:schoolboard_id]加载记分板,以便我们可以使用新的和创建操作。

class TeamsController < ApplicationController

  before_action :set_scoreboard, only: [:new, :create]
  before_action :set_team, only: [:show, :edit, :update, :destroy]

  # GET /scoreboard/:scoreboard_id/teams
  def index
    @scoreboard = Scoreboard.eager_load(:teams)
                            .find(params[:scoreboard_id])
    @teams = @scoreboard.teams
  end

  # GET /teams/1
  def show
  end

  # GET /scoreboard/:scoreboard_id/teams/new
  def new
    @team = @scoreboard.teams.new
  end

  # POST /scoreboard/:scoreboard_id/teams
  def create
    @team = @scoreboard.teams.new(team_params)

    if @team.save
      redirect_to @team, notice: 'Team was successfully created.'
    else
      render :new
    end
  end

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

    def set_scoreboard
      @scoreboard = Scoreboard.find(params[:scoreboard_id])
    end

    # Only allow a trusted parameter "white list" through.
    def team_params
      params.require(:team).permit(:name, :wins, :loss, :tie, :scoreboard_id)
    end
end