Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested fields and strong parameters

I am having a complex issue in Rails 4, which I will try to describe below. I am using simple form and awesome_nested_fields gems.

I have a bunch of events with some fields in my app

Here's my working event_controller params before the implementation of accepts_nested_attributes:

private

  def event_params
    params.require(:event).permit(:title, :description, :type_id, :price, :program,
                                  :start_date, :end_date, :image, category_ids: [])
  end

Now I would like to add some speakers to my events, and make the user decide, how many speakers he wants per event. So I'm adding the nested fields gem and making speakers a nested field, as per their documentation.

Event.rb

class Event < ActiveRecord::Base
  has_many :speakers
  accepts_nested_attributes_for :speakers, allow_destroy: true
end

Speaker.rb

class Speaker < ActiveRecord::Base
  belongs_to :event
end

Adding speakers (inside my add event simple_form_for):

  <%= f.nested_fields_for :speakers do |f| %>
      <fieldset class="item">
        <%= f.label :name %>
        <%= f.text_field :name %>

        <a href="#" class="remove">remove</a>

        <%= f.hidden_field :id %>
        <%= f.hidden_field :_destroy %>
    </fieldset>
  <% end %>

Update controller for strong parameters:

private

  def event_params
    params.require(:event).permit(:title, :description, :type_id, :price, :program,
                                  :start_date, :end_date, :image, category_ids: [],
                                  speakers_attributes: [ :name ])
  end

Now when I launch my app, upon creation of the new event I'm getting:

can't write unknown attribute `event_id'

If I remove the

speakers_attributes: [ :name ]

from the strong parameters I will be able to create my event, however when trying to view or edit it I will get

SQLite3::SQLException: no such column: speakers.event_id: SELECT "speakers".* FROM "speakers"  WHERE "speakers"."event_id" = ?

And of course there are no speakers created in the database.

>> s = Speaker.first
=> nil

I will appreciate any help or advice. Thank you!

=====

UPDATED for the duplications issue

Events controller

  def update
    @event = Event.find(params[:id])

    if @event.update(event_params)
      flash[:success] = "Event updated"
      redirect_to @event
    else
      render @event  
    end
  end

event.rb

class Event < ActiveRecord::Base

  belongs_to :type

  has_many :categorizations
  has_many :categories, through: :categorizations
  has_many :speakers
  accepts_nested_attributes_for :speakers, allow_destroy: true

  @today = Date.today

  def self.future_events
    order('start_date ASC').where('start_date >= ?', @today)
  end

  scope :current_events,  lambda { where('start_date < ? and end_date > ?', @today, @today) }
  scope :past_events,     lambda { order('end_date DESC').where('end_date < ?', @today) }

  scope :future_by_type,   lambda { |type| order('start_date ASC').where('type_id = ? and start_date >= ?', type, @today) }
  scope :current_by_type,  lambda { |type| order('start_date ASC').where('type_id = ? and start_date < ? and end_date > ?', type, @today, @today) }
  scope :past_by_type,     lambda { |type| order('start_date ASC').where('type_id = ? and end_date < ?', type, @today) }

  validates :title, presence: true

  mount_uploader :image, ImageUploader

  before_save :define_end_date
  before_save :zero_price

    private

      def define_end_date
        self.end_date ||= self.start_date
      end

      def zero_price
        if self.price.empty?
          self.price = 0
        end 
      end
end
like image 940
The Whiz of Oz Avatar asked Aug 19 '13 07:08

The Whiz of Oz


1 Answers

Now that I think about it, it might be related to strong parameters. For update to work you need to allow id attributes also. In your permit params add id for speakers and any other nested nested resources in use that will be updated.

Please give this a try:

def event_params
  params.require(:event).permit(:title, :description, :type_id, :price, :program,
                              :start_date, :end_date, :image, category_ids: [],
                              speakers_attributes: [ :id, :name ])
end 
like image 192
vee Avatar answered Sep 25 '22 16:09

vee