1

In RoR, whenever you create a nested resource, is there to set attributes during creation of a resource with a parent association, within the model?

I have this Role model that may belong_to and have_many other roles.

employee = Role.find_by_slug :employee
employee.role
=> nil
employee.roles
=> [...more roles...]
waitress = employee.roles.create(slug: :waitress)
=> #<Role id...
waitress.role
=> #<Role slug: 'employee'...
waitress.roles
=> []

The role model has a boolean attribute of subtype. Whenever I create a role from an existing role, I'd like for subtype to be set to true.

employee.subtype
=> false

And waitress would look like this:

waitress.subtype
=> true

3 Answers 3

1

Whenever I create a role from an existing role, I'd like for subtype to be set to true.

#app/models/Role.rb
class Role < ActiveRecord::Base
   belongs_to :role
   has_many   :roles

   validate :role_exists, if: "role_id.present?"
   before_create :set_subtype, if: "role_id.present?"

   private

   def set_subtype
     self.subtype = true
   end

   def role_exists
      errors.add(:role_id, "Invalid") unless Role.exists? role_id
   end
end

The above will require another db request; it's only for create & it will happen when the model is invoked (IE you can call it whatever you like when you need it).

--

An alternative to this would be to use acts_as_tree or a similar hierarchy gem.

AAT adds a parent_id column in your db, to which it will then append a series of instance methods you can call (parent, child, etc).

This would permit you to get rid of the has_many :roles, and replace it with a children instance method:

#app/models/role.rb
class Role < ActiveRecord::Base
   acts_as_tree order: "slug"
   #no need to have "subtype" column or has_many :roles etc
end

root      = Role.create            slug: "employee"
child1    = root.children.create   slug: "waitress"
subchild1 = child1.children.create slug: "VIP_only"

root.parent   # => nil
child1.parent # => root
root.children # => [child1]
root.children.first.children.first # => subchild1
Sign up to request clarification or add additional context in comments.

Comments

0

According to your description, a given Role is considered a subtype if it has no parent role. In this case, simply add the following method to Role:

def subtype?
  !self.role.nil?
end

1 Comment

You are right, according to my description this works. However, users will be using a form to create different roles. As such, I rather they specify whether or not it is a subtype for validation. That way, I can write something like: validates :role, presence: true, if: :subtype and validates :role, absence: true, unless: :subtype
0

The following changes did the trick for me:

from:

has_many :roles

to:

has_many :roles do
  def create(*args, &block)
    args[0][:subtype] = true
    super(*args, &block)
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.