0
votes

I have nested form for my GameDate model and RefereeStat model. They are connected with has_many association. Without nesting, both models are saving. But in nested form, my app won't save them. I suspect that the problem is in form, probably in association with showcase controller, but I can't figure it out.

This is output from console:

Started POST "/game_dates" for 127.0.0.1 at 2016-03-24 20:38:07 +0100 Processing by GameDatesController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"umpbTCZekqIU/g6uVdlde9fSubutgLk0Qrbb0e5GCdn3qj4/C0tmlxl/akxaM1Vmr6v8dNB8b88ATpRN8v1U2g==", "game_date"=>{"date(1i)"=>"2016", "date(2i)"=>"3", "date(3i)"=>"24", "referee_stats_attributes"=>{"0"=>{"games_count"=>"3", "showcase_id"=>"10"}}}, "commit"=>"Create Game date"} User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]] (0.4ms) BEGIN (0.3ms) ROLLBACK Showcase Load (0.8ms) SELECT "showcases".* FROM "showcases" Rendered game_dates/_form.html.haml (22.4ms) Rendered game_dates/new.html.haml within layouts/application (23.9ms)
Rendered layouts/_header.html.haml (0.7ms) Rendered shared/_flash.html.haml (0.2ms) Completed 200 OK in 148ms (Views: 138.5ms | ActiveRecord: 2.2ms)

This is GameDate model:

class GameDate < ActiveRecord::Base

  validates :date, presence: true

  has_many :referee_stats
  accepts_nested_attributes_for :referee_stats, :reject_if => :all_blank
end

Game date controller:

class GameDatesController < ApplicationController
  before_action :authenticate_user!
  before_action :user_is_admin

  def new
    @game_date = GameDate.new
    @game_date.referee_stats.build
  end

  def create
    @game_date = GameDate.new(game_date_params)
    if @game_date.save
      redirect_to showcases_path
      flash[:success] = "Game date created"
    else
      render 'new'
    end
  end

  def show
    @game_date = GameDate.find(params[:id])
  end

  def destroy
    @game_date = GameDate.find(params[:id]).destroy
    redirect_to root_url
    flash[:success] = "Game date deleted"
  end


  private

  def game_date_params
    params.require(:game_date).permit(:date, referee_stats_attributes: [ :games_count, :showcase_id ])
  end

  def user_is_admin
    unless current_user.admin?
      flash[:error] = "You don't have permission to perform this action!"
      redirect_to root_url
    end
  end
end

Referee stat model:

class RefereeStat < ActiveRecord::Base

  validates :games_count,  presence: true, numericality: {
                           only_integer: true,
                           greater_than_or_equal_to: 0 }

  validates :showcase_id,  presence: true
  validates :game_date_id, presence: true

  belongs_to :showcase
  belongs_to :game_date

end

Form:

.container
  .row
    .col-md-6.col-md-offset-3
      = simple_form_for @game_date do |f|
        = f.error_notification
        %h2.text-center Game date
        = f.input :date
        = f.simple_fields_for :referee_stats do |r|
          %h3.text-center Referee statistics
          = r.input :games_count
          = r.association :showcase, label_method: :name, value_method: :id, include_blank: false
        = f.button :submit, class: "btn btn-primary btn-sm"
2
replace ` f.simple_fields_for :referee_stats do |r|` with ` f.simple_fields_for @game_date.referee_stats do |r|` It should work.Muhammad Yawar Ali
OR just removing` @game_date.referee_stats.build` in controller will also resolve this situation.Muhammad Yawar Ali
@MuhammadYawarAli when I've removed '@game_date.referee_stats.build' fields for referee_stats deasapear. When I change my form with your first advise, I've recived this error "undefined method `has_attribute?' for #<RefereeStat::ActiveRecord_Associations_CollectionProxy:0x007f7d4051e0b8>"Nekron
Your code looks fine to me and is working for me same way. Is your code on git or you can share so that i can try to debug ?Muhammad Yawar Ali

2 Answers

1
votes

I looked into your git code and found solution :

You are not passing game_date_id from the game_date new form and it failing at game_date_id presence validation and not allowing you to save record so, its better to use association name validation to ensure presence of record.

Actually, presence validator for foreign key don’t care about record existence. It means that you are able to pass game_date_id from form.

Change the following line in referee_stat.rb & it will work for you :

validates :game_date_id, presence: true
   replace with
validate :game_date
    OR
validates :game_date, presence: true, if: -> {game_date_id.present?}

Validating foreign key and the association itself are explained at this blog.

0
votes

Currently your referee_stats_attributes are passed like such:

"referee_stats_attributes"=>{"0"=>{"games_count"=>"3", "showcase_id"=>"10"}}

But they should be passed like this:

"referee_stats_attributes"=>[{"games_count"=>"3", "showcase_id"=>"10"}]

The id "0" is not needed; Rails magic will auto-create this for you. You only need to pass an id if you're updating, and even then, it should be passed like so:

"referee_stats_attributes"=>[{"id" => 1, "games_count"=>"3", "showcase_id"=>"10"}]

I have not used simple_form_for so can't comment on the syntax, because it looks OK... but check the HTML output, your <input> for the child objects should look like this:

<input name="referee_stats[][games_count]" ... />
<input name="referee_stats[][showcase_id]" ... />