Retrieving Associated Records Dynamically (Tableize)? - ruby-on-rails

I am trying to build a generalized function that can retrieve associations of given object. The object is passed, but what associations are to be retrieved needs to be dynamic.
Using a method called associations, I can get an array of models that associate with the given object. My problem is how to take that information and use it to retrieve the rails association (using the standard a = b.models).
I am trying to use tableize but it doesn't work (getting an undefined method error)--it doesn't seem to think of it as a table name.
My code essentially boils down to:
assoc = obj.associations
tablename = assoc[0].tableize
obj.tablename.each
What is the correct way to do this?

Try using the send method:
obj.send(tablename).each

Related

access ActiveRecord Has Many associations

I have a model which has a lot of associations. What I need to do is to check whether one of those associations is not present or all of them are set correctly.
To do so, I created an array which includes all of those needs-to-be-checked fields. And created a loop through each element, but the case is that I can not access has_many related attributes with read_attribute method. It basically returns nil whenever I try to access has many associated fields.
What I am trying to do, I can access all related objects via car.drivers but I can not access the same object with car.read_attribute(:drivers) (because some of them are attributes and some are relations)
I think it's the behavior of read_attribute, so what should I use to access any (attribute or relation) on ActiveRecord object?
Regarding to the comments, it looks like no one understand what I am trying to do. I want to access the relations of one ActiveRecord object such like;
RELATIONS.each do |relation|
puts "#{relation} exists" if #object.relation.present?
end
What I do not know about this, is there any method that I can access the related objects with their string typed name. Similar to, #object.read_attribute(:attribute_name) In that way I can create a for loop, but for relations not for the attributes
To do so, I used dynamical method call. Below is an example of showing it
RELATIONS.each do |relation|
puts "#{relation} exists" unless #object.send('relation').nil?
end

Is it possible to add a variable to an object in rails?

I'm really frustrated with rails because of a ton of little problems like this.
I have a model called timelines. In it is a datetime column but the javascript that I'm passing the data too is expecting a date only. So I want to add a new string to my model object before passing it to the view. This seems impossible.
First I gather the data from the database and put it into an instance variable:
#timeline = Timeline.where(token: params[:token]).first
Then I try to add on to that variable like this:
#timeline.birthday = "1/1/2000"
I get an error that says:
undefined method birthday= for #<Timeline:0x00000105add0d0>
I'm guessing it's saying this because birthday is not a column in my database. I know it's not, and I don't care that it's not in my database. I just want to add onto my variable. Is this possible?
You need to add accessor methods to be able to get/set birthday. It won't be persisted, though.
class Timeline
attr_accessor :birthday
end
Alternative solution
The underlying problem you seem to be having ("javascript expects something else") can be solved in a couple of ways. Presenter pattern, for example. Or use ActiveModel Serializers.
This will allow you to keep the model as is, and, upon rendering, transform data to format expected by client-side.
You could convert the original datetime column to date by using:
your_column_name.strftime("%d/%m/%y")

Saving record fails due to uniqueness conflict with itself?

I have a procedure which receives two models, one which already exists, and another one which holds new attributes which I want to merge in the first one.
Since other parts of the program are holding the same reference to the new model, I can't just operate on the existing one. Therefor I do the following:
def merge(new_model, existing_model)
new_model.attributes = existing_model.attributes.merge(new_model.attributes)
new_model.id = existing_model.id
end
Now the new_model is being saved which gives me the uniqueness erorr (even though it's technically the same model). I also tried using the reload method, but that yields the same result.
Background:
The method above is run in a before_add callback on an association. I want to be able to call update on a model (with nested associations) without having to specify IDs of the nested models. This update is supposed to merge some associations, which is why I try to do the whole merge thing above.
You can't set the id of a model and then save the record expecting the id to be set since the id is the primary key of the database. So you are actually creating a whole new record and, thus, the uniqueness validation error. So you'll need to think of some other design to accomplish what you are wanting. It may help to know that what you are trying to do sounds similar to a deep_dup, except that ActiveRecord doesn't define this method (but Hash does).

cant understand meaning of following lines in haml file

#{#current_user.allowed_events.size}
#{#current_user.batch_mates.size}
link_to "<span>#{#current_user.related_colleges.size}</span>Colleges".html_safe
in above lines what are these allowed_events.size,related_colleges.size?
are these builtin functions?
Most likely allowed_events and batch_mates are either an association or method on the User model (assuming that's what #current_user references). Take a look in apps/models/user.rb and see if you find anything there.
Those methods are likely returning an ActiveRecord::Relation which is sort like a class wrapper around an array of models, typically returned from a database search. Anyway, the ActiveRecord::Relation class has a size method which is very similar to length or count.
So it's most likely just spitting out the number of allowed events and batch mates that belong to the current user.
As for the #{} that's just triggering Ruby interpolation. You could also do it this way:
= #current_user.allowed_events.size
= #current_user.batch_mates.size
As per the code, current_user is an object of User model. related_colleges and allowed_events could be associations/method/name scope in use model, you need to see your User.rb file in model to get it. I think these are associations (likely has_many) where size is the method to get the count of associated objects

Type method interfering with database type column problem

I'm using Ruby on Rails and the paths_of_glory gem
I need to access the types of achievements that a user accomplishes in order to display a picture along with each particular achievement. When I try to access it via #user.achievements.type, I get an error that says that it wants to return "array" (as in achievements is an array) instead of actually returning the elements in the type column of my database.
Since every ruby object has a method called type, my call to access the type column of the database fails. When I try to change the entry in the table, the paths_of_glory gem says it needs a type column in order to function properly.
I'm not quite sure where to go from here in order to access that column in the database. Any suggestions?
Not entirely sure what you're asking here, but maybe this will help.
For the first thing, #user.achievements is an array because you have multiple achievements, and the type method is for individual elements of #user.achievements which is why that won't work just like that. You'll have to do something like this:
#user.achievements.each do |achievement|
# Do stuff here
end
Regarding the type column, type is a reserved column in Rails used specifically for Single Table Inheritance, where multiple Rails models use a single database table. So you can't access it directly. I assume that paths_of_glory uses STI in some manner. You can access the model's class with something like achievement.class, then if you want just the name of it you can try achievement.class.to_s.
#user.achievements.each do |achievement|
model = achievement.class # => MyAwesomeAchievementClass
#image = model.picture # You could write some method in the model like this
end

Resources