I have two models, Address and User:
class Address < ActiveRecord::Base
belongs_to :resource, polymorphic: true
end
class User < ActiveRecord::Base
has_one :contact_address, class_name: "Address", as: :resource
has_one :billing_address, class_name: "Address", as: :resource
end
Problem is if I create billing_address for User it will be automatically set as contact_address, since the addresses table doesn't specify a different resource_type (both are User).
Can you give me some advice on how I should set up my models?
Thanks
I would say a billing address is more to do with an order than a person. For example, on one order I might want you to bill me at work, another at home.
Also, a person can have many addresses, but an address can also have many people. It is a network, not a hierarchy. The classic representation:
PARTY
id
type
name
PARTY_ADDRESS
id
party_id
address_id
type {home, work}
ADDRESS
id
suite
...
ORDER
id
date
customer_party_address_id
bill_to_party_address_id
ORDER_ITEM
id
order_id
product_id
price
quantity
ship_to_party_address_id
I choose easy way, added another foreign_key for addresses table. After that:
has_one :contact_address, class_name: "Address", as: :resource, foreign_key: :foreign_key
Single table inheritance can help you out. To get this to work you have to add a type column to the locations table through a migration (as you do with all Single Table Inheritance models).
class Address < ActiveRecord::Base
belongs_to :resource, polymorphic: true
end
class ContactAddress < Address
end
class BillingAddress < Address
end
class User < ActiveRecord::Base
has_one :contact_address, as: :resource
has_one :billing_address, as: :resource
end
For what it's worth, the belongs_to relationship name (:resource) is a bit weird. Maybe :addressable would make more sense?
Related
I have orders and items table. I also have a third table called orders_items. Which I learned on creating from the following link (2nd graph) http://www.tutorialspoint.com/ruby-on-rails/rails-models.htm
models/order.rb
class Order < ActiveRecord::Base
has_and_belongs_to_many :items, through: :item_order
end
models/item.rb
class Item < ActiveRecord::Base
has_and_belongs_to_many :orders, through: :item_order
end
[orders_items] table has the following:
integer :order_id
integer :item_id
Do I have to create a models/order_item.rb file to add:
belongs_to :order
belongs_to :item
If so what is the correct naming format that it should be?
Would the name for the model file [order_item.rb] correct to distinguish which table it refers to?
models/order_item.rb ??
class OrdersItem ??? < ActiveRecord::Base
belongs_to :order
belongs_to :item
end
From the API
The join table should not have a primary key or a model associated
with it. You must manually generate the join table with a migration
such as this
class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
def change
create_table :developers_projects, id: false do |t|
t.integer :developer_id
t.integer :project_id
end
end
end
Specifies a many-to-many relationship with another class. This
associates two classes via an intermediate join table. Unless the join
table is explicitly specified as an option, it is guessed using the
lexical order of the class names. So a join between Developer and
Project will give the default join table name of “developers_projects”
because “D” precedes “P” alphabetically
In your case the join table name should be items_orders.
Your model must be named OrderItem. And you don't need belongs_to in this class. The file name (order_item.rb) is correct.
I think you need this relationship to fulfill your needs, except if orders is an item too
class Order < ActiveRecord::Base
has_many :items
end
and
class Item < ActiveRecord::Base
belongs_to :order
end
this is my first question on StackOverflow :)
I'm building a Rails 4 app, having trouble to figure out a good way to load records from mutilple data models. I could hard code SQL statements like an inner join, but wondering if there's any better way. Searched in existing questions on SO, but didn't find a match.
Here are my models:
class Person < ActiveRecord::Base
has_many :addresses
end
class Address < ActiveRecord::Base
belongs_to :person
belongs_to :city
end
class City < ActiveRecord::Base
has_many :addresses
end
Question: given a person Id, how should I load its associated addresses with the city information?
Address.includes(:persons,:cities).where(person_id: person.id)
this is one of many ways.
I understand that a belongs_to puts the foreign key on the declaring model, and a has_one puts it on the other model. Does that mean there is no difference in this example?
class Category
belongs_to :blog
end
class Blog
end
class Blog
has_one :category
end
class Category
end
The only thing I can see is that the second example's nomenclature makes a little more sense.
Yes.
belongs_to expects the foreign key to be on its table whereas has_one expects it to be on the other:
# here the Category table will need to have a blog_id field
class Category
belongs_to :blog
end
# the blog table won't need anything
class Blog
has_one :category
end
has_one under the hood is similar to has_many except it adds a LIMIT 1 clause to the sql statement when you query the table.
The difference lies in the database, as you've noted. The model with the belongs_to reference must contain the foreign key for the association. When using has_one, it will expect to find a foreign key on the associated model.
How to correctly setup a User model with 2 roles, and have 2 separate profile models for each of the roles? Im confused on how to implement. Currently im using this but it fails:
models/user.rb
# id :integer ( only important columns noted to save space)
# profile_id :integer
# profile_type :string(255)
belongs_to :profile, :polymorphic => true
models/profile_student.rb:
# user_id :integer
has_one :user, as: :profile, dependent: :destroy
models/profile_tutor.rb:
# user_id :integer
has_one :user, as: :profile, dependent: :destroy
How to correctly get the profile for a user??
for example using devise.
#user = current_user.profile
I would try having two types of users: student and tutor. In order to do this, in your user table, have a column called type and put in a validation that ensures it is either student or tutor:
validates :type, :inclusion => {:in => ['student', 'tutor']}
Then create a Student model and a Tutor model. In rails, 'type' is a special kind of attribute in which rails will know that it is referring to other models. Then, in order to make profiles, you have two options. You can either say that both a student and a tutor has_one :profile, or you can separate the types of profiles.
For example, you can do:
class Student < User
has_one :profile
end
class Tutor < User
has_one :profile
end
If both profiles have similar types of information, that may work for you. However, if a tutor and student have considerably different profiles, try something like this:
class Student < User
has_one :student_profile
end
class Tutor < User
has_one :tutor_profile
end
and then create a separate model for each type of profile.
By using this 'type' column, you can make it so that students and tutors inherit all the methods and properties of users, but can also have their own distinct properties and methods.
I'm trying to figure out the best way to setup my database and models for the following scenario.
A user can like an infinite number of songs.
A song can be liked once by an infinite number of users.
I have these tables:
songs, users, likes etc... Following RoR conventions.
The table named likes has these foreign keys: user_id, song_id. And also a field named 'time' to save a timestamp when the song was liked.
I'm not sure of how to do this, I would like to be able to use code like this in my controllers:
User.find(1).likes.all
This should not return from the likes table, but join the songs table and output all the songs that the user likes.
What are the best practises to achieve this in Ruby on Rails following their conventions?
Unless you need to act specifically on the likes table data, the model itself is probably not necessary. The relationship is easy:
class User < ActiveRecord::Base
has_and_belongs_to_many :songs
end
class Song < ActiveRecord::Base
has_and_belongs_to_many :users
end
This will join through the currently non-existent song_users table. But since you want it to join through likes you can change each one to this:
has_and_belongs_to_many :songs, :join_table => 'likes'
If you want to be able to call User.find(1).likes and get songs, then change the user's version to this:
class User < ActiveRecord::Base
has_and_belongs_to_many :likes, :join_table => 'likes', :class_name => 'Song'
end
And you could change the songs version to something like this:
class Song < ActiveRecord::Base
has_and_belongs_to_many :liked_by, :join_table => 'likes', :class_name => 'User'
end
This will give you Song.find(1).liked_by.all and give you the users (You could keep it to users if you wanted using the first version)
More details on habtm relationships can be found here: http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many
Edit to add
If you want to act on the join table for whatever reason (you find yourself needing methods specifically on the join), you can include the model by doing it this way:
class User < ActiveRecord::Base
has_many :songs, :through => :likes
has_many :likes
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :song
end
class Song < ActiveRecord::Base
has_many :users, :through => :likes
has_many :likes
end
This will let you do User.find(1).songs.all, but User.find(1).likes.all will give you the join data