Let's say I got tasks and lists with an has_and_belongs_to_many relationship:
class Task < ActiveRecord::Base
attr_accessible :content, :due_date
has_and_belongs_to_many :lists
end
class List < ActiveRecord::Base
attr_accessible :title, :user_id, :space_free_title
has_and_belongs_to_many :tasks
end
Also I got the related model/table since a task can be on many lists:
class ListsTasks < ActiveRecord::Base
attr_accessible :list_id, :task_id
end
Now I know how to get all ListsTasks by the list_id:
ListsTasks.find_all_by_list_id(1)
But how do I get the contents of a task based on ListsTasks?
Your ListsTasks model is unnecessary and is not being used by the two associations in your List and Task models.
Are you looking for something like List.find(1).tasks to get the tasks on that list?
Related
I have two models to make a relationship between them, where I need to access stores of a radar and the radars of a store. A radar could monitoring zero or many stores. A store could belong to zero, one or many radars.
I would like to have something like this:
store = Store.first
store.radars #all radars of the store location
And the opposite too:
radar = Radar.first
radar.stores #all stores of the radar location
My classes:
class Store < ActiveRecord::Base
attr_accessible :title, :description, :user, :store_group, :city,
:neighborhood, :sublocality, :post_code, :route,
:street_number, :latitude, :longitude
end
class Radar < ActiveRecord::Base
attr_accessible :name, :radius, :latitude, :longitude, :user
end
How can I create a migration to handle this?
What you are looking for is a has_and_belongs_to_many association between radars and stores. The question you need to ask your self is will there ever be any attributes on the the joining between the two models? If so you might considering using an explicit join model, that will hold those attributes. In that case you would be looking at a has_many :through association.
see http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association for information on the HABTM association.
your migration for a HABTM would be something like this.
class CreateRadarStores < ActiveRecord::Migration
create_table :radars_stores, :id => false do |t|
t.belongs_to :radar
t.belongs_to :store
end
end
The order of the table name is important, since by default rails creates it in alphabetical order of the models.
Your models would need to be updated to include the HABTM
class Store < ActiveRecord::Base
has_and_belongs_to_many :radars
....
end
class Radar < ActiveRecord::Base
has_and_belongs_to_many :stores
....
end
or if using a has many :through look here http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Building that join model would be up to you depending upon attributes reuqired.
I have a stores application on github. I'm trying to implement counter_cache for two models, 1. Divisions model and 2. Products model. For some reason I'm not sure of the counter cache(divisions_count) doesn't get incremented automatically for the Company model whenever I create a new Division and similarly the products_count doesn't get incremented for the Divisions model when I add a new product to the division.
I'm on rails 3.2.11 and on ruby 1.9.3-p327
My application is only at POC level.
PFB the model structure wrt Company, Division and Product:-
company.rb
class Company < ActiveRecord::Base
attr_accessible :contact_no, :email_id, :fax_no, :name, :website, :divisions_count
has_many :divisions #just added divisions_count to attr_accessible not sure if it helps
has_many :products, :through => :divisions
end
division.rb
class Division < ActiveRecord::Base
attr_accessible :company_id, :name, :products_count
#just added products_count to attr_accessible not sure if it helps
belongs_to :companies, :counter_cache => true
has_many :products
end
product.rb
class Product < ActiveRecord::Base
attr_accessible :division_id, :model, :name, :price
belongs_to :divisions, :counter_cache => true
end
In case you want to refer to the migrations that I've created for the counter cache implementation , you may find them here.
I believe the problem is that you’ve set up belongs_to incorrectly by using the plural name. Switching to singular solves the problem, i.e.
# pseudo diff:
- belongs_to :companies, :counter_cache => true
+ belongs_to :company, :counter_cache => true
- belongs_to :divisions, :counter_cache => true
+ belongs_to :division, :counter_cache => true
When editing models/associations I found it helpful to think of an actual instance. So, it makes sense that the “Windows”-division belongs to “Microsoft”-company, but it makes no sense that it belongs to “Microsoft”-companies. Or just remember belongs_to is always singular and has_many is always plural.
If you need your divisions to belong to multiple companies, you need to use a different association called “has and belongs to many” or HABTM for short (see [1]).
[1] http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
I have a model named Container. This model just has a list of associated Links. So I created tables containers, links and containers_links. Now I want to connect my two models. So I did
class Container < ActiveRecord::Base
has_many :links, :through => :containers_links
end
class Links < ActiveRecord::Base
has_many :containers, :through => :containers_links
end
But I have an error because I don't have reflection with containers_links in my model. I can add something like
has_many :containers_links
But I don't have a model ContainersLinks (and I don't want to create one). What should I do?
You can use has_and_belongs_to_many relationship
class Container < ActiveRecord::Base
has_and_belongs_to_many :links
end
class Links < ActiveRecord::Base
has_and_belongs_to_many :containers
end
But you still need to create join table.
I have three models:
Class Project < ActiveRecord::Base
has_many :tasks
has_many :tags, :through => :tasks
end
Class Tasks < ActiveRecord::Base
belongs_to :project
has_and_belongs_to_many :tags
end
Class Tags < ActiveRecord::Base
has_and_belongs_to_many :tasks
has_many :projects, :through => :tasks
When I open up console, I can get my Project and Task information as expected:
Tag.find(1).projects
Tag.find(1).tasks
If I want, I can get all the tasks for each project regardless of the tag:
Project.find(1).tasks
For whatever reason, I can't access tasks if I get projects by tag...
something = Tag.find(1).projects
something.tasks
...I get the error:
undefined method `tasks' for #<ActiveRecord::Relation:0x007feae4af0e70>
I've looked for a couple hours and can't find anything that corrects this problem. Based on everything I've found, it should be working... but it's not.
I'm using Rails 3.2.3.
Shouldn't Tag.find(1).tasks give you the same result?
Anyway, the problem you're facing is that you're trying to retrieve an association from a Relation object instead of an instance of your model. Relations can be used to chain query conditions, but you can't directly reference associations from them. So, to get your example working, you'd need to do
p = Tag.find(1).projects.includes(:tasks)
Then reference tasks like this: p[0].tasks.
However I'd just make sure that Tag.find(1).tasks will generate the same SQL and ultimately return the same collection of tasks.
I'm trying to do a basic model association in rails.
Basically I have a List table which stores item_id and user_id.
One user can create multiple "list-items."
Is this the correct way to do it?
Thanks.
class Item < ActiveRecord::Base
has_many :users, :through => :lists
end
class User < ActiveRecord::Base
has_many :items, :through => :lists
end
class List < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
Depending on what you want to reach, your solution is the right one (or not). I see the following cases:
You want to create an n:m association between items and users. So each item could be referenced by many users, and each user references many items. If this is the right context, then your solution is the right one. See the Rails Guides: Associations for more information on that.
An alternative for that situation could be to use the has_and_belongs_to_many Association. The situation is the same, but it does not make sense to talk about lists, there will be no model object for it.
If each users may have many lists, and each list may have many items, your solution would be wrong. This would be no n:m association with list as the join table in between, but two 1:n relations.
The code for the third example would look like that:
class User < ActiveRecord::Base
has_many :items, :through => :lists
has_many :lists
end
class List < ActiveRecord::Base
has_many :items
belongs_to :user
end
class Item < ActiveRecord::Base
belongs_to :list
end
In the first solution, you should add the relations for users to lists and items to list:
class Item < ActiveRecord::Base
has_many :lists
has_many :users, :through => :lists
end
class User < ActiveRecord::Base
has_many :lists
has_many :items, :through => :lists
end
If the "list" entity truly is a pure association/join, that is, it has no inherent attributes of its own, then you can simplify a bit and use has_and_belongs_to_many. Then you don't need a "List" class.
class Item < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :items
end
Rails will look for the references in a "items_users" table, so in your migration, you need to create it a la:
create_table :items_users, :id => false do |t|
t.references :users, :items
end
Many people will tell you to always use has_many :through, but others (like me) will disagree - use the right tool for job.