Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Variable Name as Attribute in Rails

I want to DRY up my Rails code by making a common method that will be reused. In order to do so, I have to make some field/attributes and the class name that is used in the code variables, so it can work for the three models (and their fields) with the same code. I tried to learn from this question and this one, but I haven't been able to get it to work.

In my model, I have this:

def self.update_percentages    
  update_percentages_2(User, "rank", "top_percent")   
end   

def self.update_percentages_2(klass, rank_field, percent_field)
  rank_class = (klass.name).constantize
  total_ranks = rank_class.maximum(rank_field)
  top_5 = (total_ranks * 0.05).ceil 

  rank_class.find_each do |f|
    if f.send("#{rank_field}") <= top_5
      f.send("#{percent_field}", 5)
      f.save
    end
  end 
end

With this code, I get ArgumentError: wrong number of arguments (1 for 0). When I start commenting lines out to narrow down the problem, it seems that the f.send("#{percent_field}", 5) causes the error.

And if I add: percent_field = (percent_field).constantize

I get: Name Error: wrong constant name top_percent.

Can someone please help me determine what I'm doing wrong?

like image 826
yellowreign Avatar asked Nov 08 '25 11:11

yellowreign


2 Answers

If you want to assign to an attribute, you need the method name with the equal sign:

f.send("#{percent_field}=", 5)

Also, this:

rank_class = (klass.name).constantize

is equivalent to this:

rank_class = klass
like image 127
Mori Avatar answered Nov 10 '25 00:11

Mori


I would rewrite your method to update all qualifying records in on transaction.

def self.update_percentages_2(klass, rank_field, percent_field)
  top_5 = ( klass.maximum(rank_field) * 0.05).ceil   
  klass.where("#{rank_field} <= ?", top_5).update_all(percent_field => 5)
end

BTW

Here is an answer to your original question.

like image 25
Harish Shetty Avatar answered Nov 10 '25 01:11

Harish Shetty



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!