I have the following relations:
reservation.rb
has_many :room_requests, dependent: :destroy, inverse_of: :reservation
accepts_nested_attributes_for :room_requests, allow_destroy: true
has_many :rooms, through: :room_requests
room_request.rb
belongs_to :reservation
belongs_to :room
room.rb
has_many :room_requests
has_many :reservations, through: :room_requests
And I'm trying update the attribute 'status' from rooms that belong to certain reservations. Something like:
Reservation.joins(:rooms).update_all('rooms.status': 'to_clean')
But evidently it doesn't work like this. I want to do it in a single query but I can't quite grasp it. What am I missing?
In the end I couldn't do the query that way because what I needed to update was on the Room model, and the query was being done in the Reservation model. I needed to reverse it, and came up with this:
Room.where(id: RoomRequest.where(reservation: Reservation.checked_in).select(:room_id)).update_all(status: Room.statuses[:to_clean])
You should link your Reservations model also with Rooms via a has_many, through: room_requests..
Once done you can easily go with:
Reservations.rooms.status.update_all('rooms.status': 'to_clean')
However, make sure that your room_requests are available and that reservations are thus assigned to rooms via the room_requests.
Cheers,
T
Related
A user can teach many topics, and each topic can have many lessons.
A user can join lessons created by other users.
(1) is pretty simple and I implemented it as follow:
#user.rb
has_many :topics
has_many :lessons, through: :topic
#topic.rb
has_many :lessons
#lesson.rb
belongs_to :topic
belongs_to :user
(2) is a many-to-many relationships and I think a join table - let's call it matches (extra points to help me find a better name!) - is required.
If I add the following
#user.rb
.
.
has_many :lessons, through: :match
#lesson.rb
.
.
has_many :users, through: :match
#match.rb
belongs_to :lesson
belongs_to :user
I think I will get an error since Rails cannot get the difference between the two relationships while calling #user.lessons, for example.
What can be a correct approach?
p.s. I see there are many questions similar to this one but I was not able to find a proper solution to my problem.
I think you should name the join table user_lessons rather than match being a convention in Rails for join tables.
After renaming, I think you should rather have it like this:
user.rb
has_many :user_lessons
has_many :subscribed_lessons, through: :user_lessons, source: :lesson
Also note that your user
has_many :lessons, through: :topics #not :topic
Let me know if that works.
I have two models: Orders and Items. This is a many to many relationship, but I'm unsure if HMT is correct
Order model:
-user_id
-transaction_cost
-delivery_time
Item model:
-price
-name
Orders should be able to get all items in the order
Items do not need to be able to get all orders
The convention on this is to use the names of both models. A good name might be ItemOrders. Has many through is almost certainly a correct choice here.
class Order < ActiveRecord::Base
has_many :item_orders, dependent: :destroy
has_many :items, through: :item_orders
end
class Item < ActiveRecord::Base
has_many :item_orders, dependent: :destroy
has_many :orders, through: :item_orders
end
class ItemOrder < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
Now you just have another ActiveRecord model, and you can add to it as you'd like. It will also be helpful for debugging. You can even use a model/scaffold generator to generate these:
rails g model item_order order:references item:references
This way you get the migrations correct right away. Nothing needs to be altered on your other models except for the above code.
I have 3 models: Guardian, Student and Organization. Guardian is connected to Student through a linking model and similarly Student is connected to Organization through a linking model. I need to get for every guardian, a list of (distinct) organizations and am wondering what the best way to do so is.
Currently I do it at the application level in the Guardian class
def organizations
orgs = []
students.each do |s|
s.organizations.each do |o|
orgs << o if !orgs.include?(o)
end
end
orgs
end
I wonder if there's a better way to do this, preferably at the database level. Any help will be appreciated.
Edit: here's a more detailed description of my models
class Person < ActiveRecord::Base
end
class Guardian < Person
has_many :student_guardian_links, inverse_of: :guardian, dependent: :destroy
has_many :students, through: :student_guardian_links, inverse_of: :guardians
end
class Student < Person
has_many :student_guardian_links, inverse_of: :student, dependent: :destroy
has_many :guardians, through: :student_guardian_links, inverse_of: :students
has_many :student_organization_links, inverse_of: :student, dependent: :destroy
has_many :organizations, through: :student_organization_links
end
class Organization < ActiveRecord::Base
has_many :student_organization_links, inverse_of: :organization, dependent: :destroy
has_many :students, through: :student_organization_links, inverse_of: :organizations
end
With relational databases is often better to think from the target set. So you want organisations with specific conditions (they have students connected to a specific guardian)
In ActiveRecord we have joins for this. It is a misnamer, as you still get only Organisation objects, it only uses a SQL-join to get them from the database, and you can specify conditions on the joined object.
Look at http://guides.rubyonrails.org/active_record_querying.html at "Joining Nested Associations" and "Specifying Conditions on the Joined Tables"
So depending on your exact model (remember you need the backward connections) it may look like this:
Organinisation.joins(:students).where('student.guardian_id' => mygivenguardian.id).distinct()
distinct is important when the join can lead to multiplications of the rows, as when a guardian is connected with more then one student to the organisation.
This should work:
students.map { |student| student.orgs }.flatten.uniq
Really the same approach you are taking. Just using a more functional approach.
Try this:
class Guardian < ActiveRecord::Base
has_many :organizations,
:through => :students
# Your existing relationships go here
end
This way you can simply call guardian.organizations.uniq to get a list of distinct organizations associated with a specific Guardian object.
I'm trying to figure out what the appropriate ActiveRecord associations would be for my models. I want to create a very barebones ecommerce site. I want to have a system for upgrading and repairing products, so having access to a user's order history is important.
My current setup is as follows:
User
has_many :products, :through => :orders
has_many :orders, :dependent => :destroy
Orders
belongs_to :user
has_many :products
Products
belongs_to :orders
My first question is does this make sense? I'm concerned with the belongs_to :orders part of Products because I want to make sure a product can be part of many different orders (for obvious reasons). If this is wrong/right, what would be the neccessary migrations needed for the correct relationship?
Thanks in advance.
I realize the post is quite old but since I was facing the same issue, it might be interesting to add some clarity for the followers. As #ManojMonga said in the comments, here you need to use a has_and_belongs_to_many association. So models will look like :
User
has_many :orders, :dependent => :destroy
has_many :products, through: :orders
Order
belongs_to :user
has_and_belongs_to_many :products
Product
has_and_belongs_to_many :orders
Then, as explained in the Active Record Association Rails Guide , you will need to create a join table that will hold the orders and products foreign key. Migration looks like this :
class OrdersProducts < ActiveRecord::Migration
def change
create_table :orders_products, id: false do |t|
t.belongs_to :order, index: true
t.belongs_to :product, index: true
t.timestamps
end
end
end
Then, after you've run the migration, you'll be able to use has_and_belongs_to_many methods.
Remember when you create your join table that in a has_an_belongs_to_many association, Active Record will look for a table named from the 2 tables name concatenated by alphabetical order. If you wish to name it otherwise, you will have to specify it in models as following :
Order
has_and_belongs_to_many :products, :join_table => "new_tables_name"
Products
has_and_belongs_to_many :orders, :join_table => "new_tables_name"
Finally, the has_many :products, through: :orders in the User's model isn't mandatory. It will just allow to access products through users.
That's it, I'll be happy if it can be of any help. I'm using Rails 4.1 by the way.
Products has_one :order. This will allow you to use things like #product.order, but it won't actually create the foreign key for order in the products database table.
this seems pretty basic stuff here, but actually i'm finding it a bit harsh to define this scenario with Rails...
Perhaps any of you can provide some guidance?
So I have three Tables, Users, Invoices, and User_Invoice_Viewers (these basically map users that have viewer access to an invoice)
Now my models :
User.rb :
has_many :invoices
has_many :user_invoice_viewers
has_many :invoices, through :user_invoice_viewers
Invoice.rb
belongs_to user_invoice_viewers
belongs_to :user
User_Invoice_Viewers.rb
belongs_to :users
belongs_to :invoices
Now this just seems wrong... I repeat has_many :invoices on User model, so i expect conflict when executing : User.invoices ...
What would be the best solution for this? I had thought of putting it all on a user_invoice table, but since i expect to have more owners than viewers, for performance reasons, i decided to build a direct dependency between invoice and its owner...
Thanks
I would consider using the :class_name option on the association, so that the two relationships are named differently. Something like this:
class User < ActiveRecord::Base
has_many :invoices
has_many :user_invoice_viewers
has_many :viewable_invoices, through :user_invoice_viewers, :class_name => "Invoice"
...
end