evaluate string to modify data model in ruby - ruby

I seem to be running into a problem with Rails 3 and I can't seem to figure it out.
Here's what I am trying to do:
att1 = "column"
att2 = "1"
final_column = "#{att1}_#{att2}"
obj.final_column = 4
====> Error
-----> NoMethodError: undefined method `final_column=' for class....
If I do this it works though:
obj.column1=4
What can I do to my final_column to make it work?
Thanks!

You want to do this:
obj.send("#{final_column}=", 4)
If you want to respect the private/protected visibliy, use public_send instead of send.

Related

Ruby Delete multiple objects by association

My app needs to destroy all of the teams that have fewer than two members.
This method seems to be working, but I'm hoping to "rubify" it to one line if possible.
#consultancy.teams.reverse.each do |team|
team.destroy if team.users.count < 2
end
I'm trying to do something more like the following, but I'm getting an error for the reject! method.
#consultancy.teams.reject!{|x| x.users.count < 2}
NoMethodError: undefined method `reject!' for #<Team::ActiveRecord_Associations_CollectionProxy:0x00000003f72850>
.delete_all also throws an error.
#consultancy.teams.select{|x| x.users.count < 2}.delete_all
NoMethodError: undefined method `delete_all' for #<Array:0x0000000b72dcf0>
Thank you in advance for any insight.
select acts on arrays, but delete_all is an active record relation method.
You could do
#consultancy.teams.select{|x| x.users.count < 2}.map(&:delete)
But a better way might be to do the count select as part of the query.
#consultancy.teams.joins(:users).group('teams.id').having('count(users.id) < 2').destroy_all

How to modify the value of a variable whose name is given

I wish to have a method that takes in a string, and then updates a variable with the name of that string. This is an example of my attempt:
#other_class = OtherClass.new()
def change_variable(variable_string)
self.#other_class.send.variable_string += 1
end
I am getting the error:
syntax error, unexpected tIVAR
with the pointer just before 'send' in the method above. Does anyone have any suggestions to make this work?
You probably want instance_variable_set http://ruby-doc.org/core-2.0/Object.html#method-i-instance_variable_set
The syntax using your variables is I think:
other_var = ('#' + variable_string).to_sym
#other_class.instance_variable_set( other_var, #other_class.instance_variable_get( other_var ) + 1 )
The immediate syntatic error is that you're using self and # wrongly.
Either one is fine but not in conjunction with each other.
So in your case self.other_class.send... would be fine but then you cant declare it as #.
As would # be but then you cant do self.
These are meant to do different things and these are that
# is an instance variable and so is self but the difference is that using # calls the attribute other_class directly as to where self calls the method other_class.
So # is both a getter and setter in one so you can do
#other_class = my_milk_man as to where
self.other_class -> self.other_class (as getter),
self.other_class = my_milk_man -> self.other_class= (as setter).

DRY code by creating ruby objects/variables dynamically

I am fairly new to Ruby. I have few lines of code I want to DRY them.
foo_attributes = params[:foo]
params.delete(:foo)
bar_attributes = params[:bar]
params.delete(:bar)
I am trying to do something like this
["foo", "bar"].each do |par|
par_attribute = params[:par]
params.delete(:par)
end
Later in my method, I need to call other methods passing the objects foo_attribute, bar_attribute.
Like:
call_foo_method(foo_attribute)
How can I do this in ruby?
Why don't you just keep the params var? Then you don't have to assign any other variable at all?
You can also DRY the first (and second example) by combinig two lines:
foo_attributes = params.delete(:foo)
bar_attributes = params.delete(:bar)

OR operators and Ruby where clause

Probably really easy but im having trouble finding documentation online about this
I have two activerecord queries in Ruby that i want to join together via an OR operator
#pro = Project.where(:manager_user_id => current_user.id )
#proa = Project.where(:account_manager => current_user.id)
im new to ruby but tried this myself using ||
#pro = Project.where(:manager_user_id => current_user.id || :account_manager => current_user.id)
this didnt work, So 1. id like to know how to actually do this in Ruby and 2. if that person can also give me a heads up on the boolean syntax in a ruby statement like this altogether.
e.g. AND,OR,XOR...
You can't use the Hash syntax in this case.
Project.where("manager_user_id = ? OR account_manager = ?", current_user.id, current_user.id)
You should take a look at the API documentation and follow conventions, too. In this case for the code that you might send to the where method.
This should work:
#projects = Project.where("manager_user_id = '#{current_user.id}' or account_manager_id = '#{current_user.id}'")
This should be safe since I'm assuming current_user's id value comes from your own app and not from an external source such as form submissions. If you are using form submitted data that you intent to use in your queries you should use placeholders so that Rails creates properly escaped SQL.
# with placeholders
#projects = Project.where(["manager_user_id = ? or account_manager_id = ?", some_value_from_form1, some_value_from_form_2])
When you pass multiple parameters to the where method (the example with placeholders), the first parameter will be treated by Rails as a template for the SQL. The remaining elements in the array will be replaced at runtime by the number of placeholders (?) you use in the first element, which is the template.
Metawhere can do OR operations, plus a lot of other nifty things.

Ruby send(attribute.to_sym) for Rails Method

I'm using Ruby 1.9.2 and need to go through all of the values for a table to make sure everything is in UTF-8 encoding. There are a lot of columns so I was hoping to be able to use the column_names method to loop through them all and encode the values to UTF-8. I thought this might work:
def self.make_utf
for listing in Listing.all
for column in Listing.column_names
column_value_utf = listing.send(column.to_sym).encode('UTF-8')
listing.send(column.to_sym) = column_value_utf
end
listing.save
end
return "Updated columns to UTF-8"
end
But it returns an error:
syntax error, unexpected '=', expecting keyword_end
listing.send(column.to_sym) = column_value_utf
I can't figure out how to make this work correctly.
You're using send wrong and you're sending the wrong symbol for what you want to do:
listing.send(column + '=', column_value_utf)
You're trying to call the x= method (for some x) with column_value_utf as an argument, that's what o.x = column_value_utf would normally do. So you need to build the right method name (just a string will do) and then send the arguments for that method in as arguments to send.

Resources