What is the exact purpose of associations? I understand what the relationships mean and when to use each type for example:
belongs_to, has_many, has_one , has_and_belongs_to_many, ect
but i dont quite understand what purpose they serve in terms of how the connect things within rails. Any input would be appreciated. Thanks!
What you're calling "associations" I would call "macros". That is, the belongs_to, has_many etc. macros are simply class methods being called on your ActiveRecord objects which, when called, define a bunch of functionality based on the association name.
So, what you're asking is: What functionality do these macro methods define? The answer for that lies within the Rails documentation for each of these methods:
has_many
belongs_to
has_one
And, even more, you should read the overall documentation on ActiveRecord::Associations::ClassMethods.
But, in short, these macros define methods with names based on the association names you pass into them. So, for example:
belongs_to :my_object
Will define, as a greatly-simplified example:
def my_object
MyObject.find_by_id(my_object_id)
end
So it's basically like metaprogramming your objects to have the methods needed to find the other, associated objects, update their collections, and so on.
Related
Rails 6/ Ruby 2.7
So I have two classes ModuleX::SubModuleA::Order and ModuleY::SubModuleB::OrderType
and I want to do something like
ModuleX::SubModuleA::Order.joins("ModuleY::SubModuleB::OrderType")...
This syntax would be pretty simple normally: ModuleX::SubModuleA::Order.joins(:order_type) but I cannot find any documentation regarding how this works for classes in modules.
The syntax of joins allows two uses: first, referencing a relation defined on the left-hand model by its (symbolic) name, or second, raw SQL. Neither method is actually impacted at all by the use of modules, because neither references the class of the model you're joining onto.
In your case, you probably want to set up a relation between orders and order types, like:
class ModuleX::SubModuleA::Order
belongs_to :order_type, class_name: 'ModuleY::SubModuleB::OrderType'
end
Then, you can just do the same syntax as you expect:
ModuleX::SubModuleA::Order.joins(:order_type).all
I am working through an old legacy project that has recently been updated. The models to the project are in an engine running separate from the controllers and views etc. The engine is running on rails 4.1.6 while the controllers etc are on Rails 3.
This has led to many issues with mass-assignment. I have created a little module that reads the db columns and white lists the attributes for that model. However in a case such as this NewsItem model which has associations and needs to accept attributes for those associations, the module doesn't work.
class Newsitem < ActiveRecord::Base
include MyAttrAccessibleModule
has_and_belongs_to_many :assets
has_and_belongs_to_many :boroughs
has_and_belongs_to_many :venues
I need to add
attr_accessible :asset1_attachment_remove,
:asset1_attachment_title,
:asset2_attachment_title,
:asset3_attachment_title,
:asset4_attachment_title,
:borough_ids,
:venue_ids
But finding all models that require this is a bit of a pain, seeing as there are well over 100.
Is there a way to highlight, find, test, discover in what other models this error might occur in also?
I think what you're looking for could be this:
Object.attributes.keys - Object.accessible_attributes
This should subtract all the whitelisted attributes from all of the available ones.
Thanks to #Stefan Dorunga for his suggestion. It led me in the right direction.
if reflect_on_all_associations(:has_and_belongs_to_many).any?
association = reflect_on_all_associations(:has_and_belongs_to_many)
association.each {|model| attr_accessible model.plural_name.singularize + "_id"}
association.each {|model| attr_accessible model.plural_name}
end
I query the model to see if it has a relationship where the relation id isnt explicitly listed and generate it dynamically.
The only downside is that I have to include the module after all the listed associations. I usually include modules at the top of a class. Whether this is standard practice or not I do not know.
I have a project that is built with a tagging model to reference three different models: artist, article, event. I have associated each model to the tagging model via has_many through:. I have two problems; both related to each other:
I have 5 "default" methods that I wish to be able to call restfully from the tagging controller/model: popular, upcoming, events, articles, and artists. Each method is designed to do exactly as it's name implies. The issue lies within these methods being a query by nature. How can I maintain a consistent schema where 5 of the many taggings models I have require a special attribute (let's call it content) that should subsequently call the appropriate method?
When calling any one of the taggings models, it will return (in it's content attribute) an array of the 3 models specified earlier. Other than adding a method within each model that contains a localized description of the model and then calling upon that type method to match another hardcoded string elsewhere, is there any alternative? I don't like how the implementation I just described requires me to hardcode values. Eek.
I'm very new to Ruby on Rails, so I apologize if this is an obvious solution. However I have spent a week looking into ways to solve this compound problem that I'm trying to solve. Any input is appreciated!
As far as i unterstand you need a polymorphic association. Because tags can be applied on different models, the clue is to treat all these models in polymorphic manner by marking them as :taggable on the association to tags.
I would just use the popular acts_as_taggable_on gem for it.
I'm using a Polymorphic relation with multiple tables. Object Window has ChartWindow, PluginWindow or PortletWindow. I used a class_eval (relate_to_details) technique to define detail tables so that each object can have it's own table with distinct attributes.
PluginWindowDetail is the detail table for PluginWindow. PluginWindow has a plugin_id (plugin_window_details.plugin_id) So, I defined a has_one association in PluginWindow ( has_one :plugin_window_detail, :dependent => :delete) because I want the Window to be deleted with the Plugin is deleted.
However, I realized that this isn't getting me what I want. Deleting the PluginWindowDetail won't delete the PluginWindow.. and since I'm using the class_eval technique instead of a regular ActiveRecord association, I'm not sure how I can do this without coding it myself (which maybe I should)
Anyways.. gists with code are here https://gist.github.com/3206666 . Any help would be appreciated.
I think the simpler way to do it is to use the before_destroy callback. It will be more flexible.
Trying to do a select field for an admin interface.
What I have is not a traditional many-to-many relationship, but I imagine the principles are the same. I have an "Event" model and an "EventRelation" model...every Event can have many sub-events, and one primary event...so EventRelation has primary_event_id and sub_event_id fields.
How would I make a select field that would allow me to specify a primary_event for any given Event?
The relevant model code:
class Event 'primary_event_id', :class_name=>'EventRelation'
has_one :primary_event_relation, :foreign_key=>'sub_event_id', :class_name=>'EventRelation'
has_one :primary_event, :through=>:primary_event_relation, :foreign_key=>"primary_event_id"
has_many :sub_events, :through=>:sub_event_relations, :foreign_key=>"sub_event_id"
end
class EventRelation 'Event', :foreign_key=>"primary_event_id"
belongs_to :sub_event, :class_name=>'Event', :foreign_key=>"sub_event_id"
end
I would use a plugin like Formtastic to accomplish this because it has support for various forms of ActiveRecord associations built into a solid alternative form handler. Just make sure you do an appropriate query with the most efficient join or include options for you model so that your view doesn't cause unnecessary database queries as it works through the associations.
As James says, Formtastic is a great way to go for this. And there are two great railscasts on how to use it.