I have a model called Event and another called Product. An event has many products and a product has many events (through the join model called Eventproduct
). I am trying to design a query that will select all products that are not in any event thats current date range matches that of another event, so when the user creates an event with a date range it will display the products that are available so that the same product cannot be at 2 events at once. Is this possible with the active records query interface or will I need to write my own specific SQL query.
My migrations looks like:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :make
t.string :model
t.integer :wattage
t.boolean :dmx
t.decimal :price
t.timestamps
end
end
end
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.datetime :start_date
t.datetime :end_date
t.timestamps
end
end
end
class AddContactToEvent < ActiveRecord::Migration
def change
add_column :events, :name, :string
add_column :events, :location, :string
add_column :events, :contact_number, :string
end
end
class CreateEventproducts < ActiveRecord::Migration
def change
create_table :eventproducts do |t|
t.references :product
t.references :event
t.timestamps
end
add_index :eventproducts, :product_id
add_index :eventproducts, :event_id
end
end
Here are the associated models:
class Event < ActiveRecord::Base
attr_accessible :end_date, :start_date, :products, :lightings, :name, :location, :contact_number, :product_ids
has_many :products, :through => :Eventproduct
has_many :Eventproduct
validates_presence_of :name, :message => "can't be blank"
validates_presence_of :location, :message => "can't be blank"
validates_presence_of :contact_number, :message => "A telephone number is needed so that we can contact you if we have any problems"
validates_presence_of :start_date, :message => "can't be blank"
validates_presence_of :end_date, :message => "can't be blank"
end
class Eventproduct < ActiveRecord::Base
belongs_to :product
belongs_to :event
# attr_accessible :title, :body
end
class Product < ActiveRecord::Base
validates :price, numericality: {greater_than_or_equal_to: 0.01}
attr_accessible :make, :model, :wattage, :dmx, :price
end
They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.
An instance of ActiveRecord::Base is an object that represents a specific row of your database (or might be saved into the database). Whereas an instance of ActiveRecord::Relation is a representation of a query that can be run against your database (but wasn't run yet).
ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code.
I figured out a query that could help you. You'd have to work out the conditions for the time range and the logic for it.
The query should look something like
Product.joins(:events).where("events.start_date <= :start_date", {start_date: Time.now})
The where clause should contain your logic to filter the events you don't need. Again that piece of code should get you started. So to answer your question, it is possible. Look at the query you get in return and work around that to make the condition that fits your needs. Also, take a look at this link which should help you modify the where clause the way that I did: http://guides.rubyonrails.org/active_record_querying.html
Hope this helps you!
Update:
You might have to do some set difference along with a Product.all to include those products that do not have events at all because that query will return empty if the product does not have a event in the EventProduct table. It might not be efficient but it should work depending on what you need.
Product.all - Product.joins(:events).where("condition reversed")
That should return all the Products that do not meet your condition including those that do not have events yet.
Try this one: Product.includes(:Eventproduct).where(eventproducts: { event_id: nil }).group('products.id')
.
Note that it is the name of the table inside where
condition. Also do not forget to add association for Eventproduct to your Product model: has_many :Eventproduct
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With