Rails 4 SQL query rails way - ruby-on-rails

i have this query, which I want to se in rails way. Could please anyone help me here?
select * from users
,buyer_events
,supplier_events
where (users.id = buyer_events.buyer_id
or users.id = supplier_events.supplier_id)
and supplier_events.event_id = 11
and buyer_events.event_id = 11;
PostgreSQL
If more information is needed just write in comments :)

I guess it should be something like this:
class User
has_many :supplier_events
has_many :buyer_events
scope :with_event, ->(event_id) {
joins(:supplier_events, :buyer_events).merge(supplier_events.for_event(event_id)).merge(buyer_events.for_event(event_id))
}
end
class SupplierEvent
belongs_to :supplier, class_name: :User
belongs_to :event, class_name: :Event
scope :for_event, ->(event_id) { where(event_id: event_id) }
end
class BuyerEvent
belongs_to :buyer, class_name: :User
belongs_to :event, class_name: :Event
scope :for_event, ->(event_id) { where(event_id: event_id) }
end
Then issue:
User.with_event(11)

class User < ActiveRecord::Base
...
def self.buyers_and_suppliers user_id
joins(:buyer_events, :supplier_events).where(users: {id: user_id}, supplier_events: {event_id: 11}, buyer_events: {event_id: 11})
end
...
end

Related

How to merge two double joins in ActiveQuery

I have two double joins (I believe that's what they would be considered) and it just seems awfully slow to do them separately. I know there are debates as to whether or not an individual query is quicker than multiple queries and vice versa but I am willing to try anything.
Here are my existing statements:
line_stops = OpsHeader.joins(
ops_stop_rec: :driver_header
)
.select(
:pbbname,
:pb_net_rev,
:ops_driver1,
:pb_id,
:ops_stop_id,
:dh_first_name,
:dh_last_name,
:ops_delivered_time
)
.where(
:ops_stop_rec => {
ops_arrive_time: params[:startDate] .. params[:endDate]
})
line_items = OpsHeader.joins(
ops_stop_rec: :ops_line_items
).select(
:pbbname,
:opl_amount,
:pb_id,
:ops_type,
:ops_stop_id,
:ops_order_id,
:ops_driver1,
:ops_delivered_time
)
.where(
:ops_stop_rec => {
ops_arrive_time: params[:startDate] .. params[:endDate]
}
)
Just for reference, I am pulling these from an old Firebird Database and the server hardware is not necessarily quick either, so there may be more at play than I am thinking. Also, I have to data manipulation on top of that before I serve it to the client.
Anyway, here are my associations:
class OpsHeader < ApplicationRecord
belongs_to :pb_bill
belongs_to :pb_master
has_many :ops_stop_rec, foreign_key: 'ops_order_id'
self.table_name = 'OPS_HEADER'
self.primary_key = 'pb_id'
end
class OpsStopRec < ApplicationRecord
#belongs_to :ops_order
#belongs_to :ops_im_equip
belongs_to :ops_header, foreign_key: 'pb_id'
belongs_to :driver_header, foreign_key: 'ops_driver1'
has_many :ops_line_items, foreign_key: 'opl_stop_id'
self.table_name = 'OPS_STOP_REC'
self.primary_key = 'ops_stop_id'
end
class OpsLineItem < ApplicationRecord
#belongs_to :opl_order
#belongs_to :opl_stop
belongs_to :ops_stop_rec, foreign_key: 'ops_stop_id'
self.table_name = 'OPS_LINE_ITEMS'
self.primary_key = 'opl_stop_id'
end
class DriverHeader < ApplicationRecord
#belongs_to :dh_paythru
has_many :ops_stop_rec, foreign_key: 'ops_driver1'
self.table_name = 'DRIVER_HEADER'
self.primary_key = 'dh_id'
end
What you're looking for is a union operator. There is a gem which can handle it for you.
Or try using using two left outer joins and add an OR condition.

Association in rails Model

Below is the model Structure.
class UserFamilyRole < ActiveRecord::Base
belongs_to :user_family
belongs_to :user_role
belongs_to :organization
end
class UserFamily < ActiveRecord::Base
has_many :user_family_roles
has_many :user_roles
end
I am looking for below result from the above UserFamilyRole table.
{
user_family1: [user_role1, user_role2],
user_family2: [user_role1, user_role2, user_role3]
...
}
I achieved this Result from below query:
user_family_roles = UserFamilyRole.where(:organization_id => org_id)
results = {}
juser_family_roles.each do |user_family_role|
user_family = UserFamily.find(user_family_role.user_family_id)
result[user_family.name] = user_family.user_roles.collect(&:title)
end
puts results
But Above query doesn't look optimized one so can anyone help me to write the optimized query.
In our App org_id is present.

Chain wheres with joins ActiveRecord

I'm trying to do something like this:
filter_categorys = params[:filter_categorys]
companies = Company.where('id_category = (?)', filter_categorys).joins(:subsidiary).where('zone = Nuñez')
And it's not working....
So, I need to get all my companies that have an id_category and that they have at least one subsidiary within the 'zone'.
I guess this is not the way... please HELP ! :D
Company.rb:
class Company < ActiveRecord::Base
has_many :subsidiary, :foreign_key => :id_company
has_many :benefit, :foreign_key => :id_company
set_primary_key :id_company
self.table_name = 'tbl_companys'
end
Subsidiary.rb:
class Subsidiary < ActiveRecord::Base
belongs_to :company
set_primary_key :id_subsidiary
self.table_name = 'tbl_subsidiaries'
end
You have to "tell" the where clause that the zone is in the subsidiary table:
Company.where(id_category: filter_categorys).joins(:subsidiary).where(subsidiary: { zone: 'Nuñez' }
If it says "relation subsidiary was not found", try with:
Company.where(id_category: filter_categorys).joins(:subsidiary).where(tbl_subsidiaries: { zone: 'Nuñez' }

ruby on rails, has_many, define class name for polymorphic relationship

This is my code for moving data from my old database:
class Old < ActiveRecord::Base
establish_connection :old_version
self.abstract_class = true
class Recipe < self
set_table_name :recipes
has_many :uploaded_files, :as => :storage
end
class UploadedFile < self
set_table_name :uploaded_files
belongs_to :storage, :polymorphic => true
end
end
When I run the following code
Old::Recipe.all.each do |recipe|
puts recipe.uploaded_files.to_sql
end
It performs this SQL
SELECT `uploaded_files`.* FROM `uploaded_files` WHERE `uploaded_files`.`storage_id` = 38 AND `uploaded_files`.`storage_type` = 'Old::Recipe'
The problem is that I get:
`storage_type` = 'Old::Recipe'
But I need:
`storage_type` = 'Recipe'
How can I change the class for a polymorphic relationship?
The doc for has_many doesn't give me an answer.
Recently I had similar problem, this is a solution that worked for me in rails 4.2:
class Recipe < self
set_table_name :recipes
has_many :old_files, -> (object) { unscope(where: :storage_type).where(storage_type: 'Recipe') }, class_name: 'UploadedFile'
end
You have to add unscope(:where) to remove condition uploaded_files.storage_type = 'Old::Recipe' from query.
The answer by santuxus above is working properly for rails 4.2+
However, for lower versions, you could try overwriting the association like so:
class Recipe
has_many :uploaded_files, conditions: { storage_type: 'Recipe' }, foreign_key: :storage_id
end
Unfortunately, for now I found only one way to do that:
class Old < ActiveRecord::Base
establish_connection :old_version
self.abstract_class = true
class Recipe < self
set_table_name :recipes
has_many :old_files,
:class_name => 'UploadedFile',
:finder_sql => Proc.new {
%Q{
SELECT uploaded_files.*
FROM uploaded_files
WHERE uploaded_files.storage_id = #{id} AND
uploaded_files.storage_type = 'Recipe'
}
}
end
class UploadedFile < self
set_table_name :uploaded_files
belongs_to :storage, :polymorphic => true
end
end
namespace :old do
task :menu => :environment do
Old::Recipe.all.each do |recipe|
puts '~' * 50
puts recipe.id
recipe.old_files.to_a.each do |file|
puts file.storage_id, file.storage_type
end
end
end
end
very very sad

Rails 3 find all associated records has_many :through

I would like to list all posts that are connected with some specific category and classroom.
I have:
class Post < ActiveRecord::Base
has_many :category_posts
has_many :categories, :through => :category_posts
has_many :classroom_posts
has_many :classrooms, :through => :classroom_posts
end
class Category < ActiveRecord::Base
has_many :category_posts
has_many :posts, :through => :category_posts
end
class CategoryPost < ActiveRecord::Base
belongs_to :category
belongs_to :post
end
class Classroom < ActiveRecord::Base
has_many :classroom_posts
has_many :posts, :through => :classroom_posts
end
class ClassroomPost < ActiveRecord::Base
belongs_to :classroom
belongs_to :post
end
And I wanna do something like this
Post.where(["category.id = ? AND classroom.id = ?", params[:category_id], params[:classroom_id]])
It indeed is very simple task, but I don't know what I should be looking for (keywords).
It's the same problem like this, but in rails.
EDIT:
I added more details to the question.
This works, but only if I have both params specified. Witch is not always the case - I dont know what params would be specified.
Post.joins(:categories, :classrooms).where(["categories.id = ? AND classrooms.id = ?", params[:classroom_id], params[:category_id]])
Category.find(params[:category_id]).posts
Also take a look at the guides:
Guides for Rails 2.35
Guides for Rails 3.0
Here is what I would do in Rails 3:
In post.rb:
def self.in_category(category_id)
if category_id.present?
join(:category_posts).where(category_posts: {category_id: category_id})
else
self
end
end
def self.in_classroom(classroom_id)
if classroom_id.present?
join(:classroom_posts).where(classroom_posts: {classroom_id: category_id})
else
self
end
end
I do not join Classroom or Category since it makes more work for DBMS and this is not required.
Now, you can do:
Post.in_category(params[:category_id]).in_classroom(params[:classroom_id])
I haven't tested it though. So do not hesitated to ask if needed.
I think that should work:
Post.joins(:category_posts, :classroom_posts)
.where(
["category_posts.category_id = ?
AND classroom_posts.classroom_id = ?", params[:category_id], params[:classroom_id]])
This will traslate to a SQL like :
SELECT
p.*
FROM
posts AS p
INNER JOIN
category_posts AS cap ON cap.id = p.category_posts_id
INNER JOIN
classroom_posts AS clp ON clpid = p.classroom_posts_id
WHERE
cap.category_id = '1' AND clp.classroom_id = '1'
;
As to whether to use :include or joins on Post look at this answer on stackoverflow.
Sounds like you need an if statment.
if params[:category_id] && params[:classroom_id]
Post.joins(:categories, :classrooms).where("classrooms.id" => params[:classroom_id], "categories.id" => params[:category_id]])
elsif params[:category_id]
Category.find(params[:category_id]).posts
else
Classroom.find(params[:classroom_id]).posts
end

Resources