4

I'm making a Rails 4 application. Each incident belongs to a user. Each incident has many events. I want that I can create an Incident with current_user.incidents.new and pass it an attribute message which exists in the Event model. On creation, I wish to create a new event with the said message.

Here's my Incident model.

class Incident < ActiveRecord::Base
  # The 'incident' model.
  # Incidents are created by Users (belongs_to :user)
  # Incidents may be public or private.
  # Incidents have many events (identified, fixing, etc.)

  belongs_to :user
  has_many :events
  validates :name, presence: true, length: {maximum: 256}
  validates_presence_of :component
  validates_presence_of :public
  validates_presence_of :user_id

  attr_accessor :message
  validates_associated :message, presence: true

  def message
    Event.find_by_incident_id(self.id).message
  end

  def message=(value)
    self.events.new(message: value, status: self.status)
  end

  private
    def incident_params
      params.require(:incident).permit(:name, :status, :user_id, :message)
    end

end

But, when I run @i = Incident.new(message: 'something'), I get ActiveRecord::UnknownAttributeError: unknown attribute 'message' for Incident.

Please help me figure this out.

Umang Raghuvanshi
  • 1,228
  • 15
  • 34
  • 2
    You will need [`accepts_nested_attributes_for`](http://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for) so that the Incident knows what to do with this attribute. then your `params` should be `.permit(:name,:status,:user_id,event_attributes: [ :message ])` This will also require changes to your form to use `fields_for` that references a new event. [This Tutorial](https://gorails.com/episodes/forum-nested-attributes-and-fields-for) might help better than my explanation. – engineersmnky Sep 22 '15 at 14:15

2 Answers2

2

The problem is that you're passing the values to the default ActiveRecord::new method for Incident, which won't care about your getters, setters and accessors, it goes straight to the columns.

Some people override or adapt the build method that can implement clever logic like you require, without affecting the base initialize method.

Matt
  • 13,948
  • 6
  • 44
  • 68
1

Because your Incident model inherits from ActiveRecord::Base, it inherits the constructor. The ActiveRecord constructor only accepts model attributes (db columns) as params. You are trying to call an arbitrary instance method. You could create a class method that creates an instance then adds the message:

def self.create_with_message(msg)
   i = Incident.new
   i.message(msg)
   return(i)
end
Daiku
  • 1,237
  • 11
  • 20