sebkkom
sebkkom

Reputation: 1446

Simple association architecture and implementation in ruby on rails

Quick question about a simple problem I am facing (and I want to use as a way to understand a few things about associations and rails in a deeper level). Here goes:

The two associated models are

class Employee < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :age

  belongs_to :role
  attr_accessible :role_id
end

class Role < ActiveRecord::Base
  attr_accessible :title
  attr_accessible :salary

  has_many :employees
end

so that every new employee has a fixed salary, according to his role (which is the case most of the times). However, what if I want to set a different salary for a specific employee?

Using simple_form I have so far written the following:

<%= f.input :name, label: 'Employee Name', :required => true %>
<%= f.association :role, as: :radio_buttons, :required => true %>
<%= f.input :salary, label: 'Employee Salary', :input_html => { :value => 0 }, :required => true %>

Which of course gives me a can't mass assign protected attributes: salary error.

To fix that, I added attr_accessible :salary to the Employee model but that just changed the error to unknown attribute: salary.

From what I understand I have to first change something in the new employee and then also in the employee model and controller so it accepts a value for the salary and knows how to handle it, right?

I 've also seen accepts_nested_attributes_for used but I am not entirely sure in which side of the association it should go - as I am not entirely sure the association is architectured in the best way either.

Upvotes: 0

Views: 150

Answers (1)

deefour
deefour

Reputation: 35350

You need to add a salary column to your employees table if you are in fact wanting to allow a custom salary to be specified on the Employee. In your terminal, create a new migration and apply it

rails generate migration AddSalaryToEmployees salary:integer
RAILS_ENV=development rake db:migrate

By the way, you don't need to call attr_accessible multiple times; it accepts an arbitrary # of symbols

attr_accessible :name, :age, :role_id, :salary

Also, since you mentioned it, I'll comment on it: accepts_nested_attributes_for currently has no place in your models (given the code you've shown so far).


To answer the questions raised in your comment:

Isn't that duplication of code (having salary in both models I mean)?

No, they serve two different purposes. :salary in Role is the default salary applied to all Employees associated with that Role. :salary on Employee is an 'override' for special circumstances where an Employee's salary doesn't fit the mold of the Role they're associated with.

  • It wouldn't make sense to create a custom Role just for this purpose (assuming the custom salary is the only difference for the Employee)
  • You can't change the salary on the Role itself, because that would affect the salary of the other Employees associated with that Role

And doesn't that need another method (to make sure that the role salary is set as the employee's salary if none is specifically set)?

Another method? No. Customizing the existing attr_reader for salary on Employee to return the default from the Role if an 'override' hasn't been set? If you want

def salary
  return role.salary if read_attribute(:salary).blank?
  read_attribute(:salary)
end

Upvotes: 1

Related Questions