Home > Software design >  Set a reference field for all saved objects
Set a reference field for all saved objects

Time:01-11

My application has a Group object, of which a user has many. The navbar displays which group is currently selected, and the objects displayed on various pages are based on this. A number of my models have 'group_id' fields, and I'd like for these fields to be populated with the id of the currently selected group when they're saved.

In my application controller I have a helper_method which returns the current_group however this can't and shouldn't be accessed from a model which is the DRYest way I could think of doing this.

#inhereted_model.rb
before_save :assign_group_reference  

def assign_group_reference
  self.group_id = current_group.id
end

Is there an efficient and DRY way to do this that I'm missing?

CodePudding user response:

You are right; any controller helper-methods cannot and should not be accessed directly from a model method.

I think a standard DRY way is to set the parameter of a model in your Controller methods. For example, do as follows in your Controller(s):

# In a Controller
def my_helper(mymodel)
  mymodel.group_id = current_group
    # where current_group is your Controller helper method to obtain the group name.
end

def create  # or update etc.
  @mymodel = set_my_model  # your arbitrary method to set a model
  my_helper(@mymodel)
  respond_to do |format|
    if @mymodel.save
      format.html { redirect_to @mymodel, notice: 'Success.' }
    else
      raise
    end
  end
end

If you want, you can write my_helper (which in this case takes no argument and sets the instance variable @mymodel instead of a local variable) in before_action in combination with only or except, where you make sure the method is called after a model @mymodel is set, in order to avoid calling my_helper repeatedly in many methods in the Controller.

Alternatively, if you really want to set it at a model level for some reason, a potential workaround is to use a Ruby Thread variable, like the following.

# In a controller
def create
  model = set_my_model  # Arbitrary routine to set a model
  Thread.new{
    Thread.current.thread_variable_set(:grp, current_group)
      # where current_group is your Controller helper method to obtain the group name.
    model.save!
      # In the model, you define a before_save callback
      # in which you write something like
      #   self.group_id = Thread.current.thread_variable_get(:grp)
  }.join
end

But I think this is a little dirty hack and I would avoid it in principle.

  •  Tags:  
  • Related