This is my Organization Model:
class Organization < ActiveRecord::Base
has_many :users
has_many :shipments, :through => :users
This is my Shipment Model:
class Shipment < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
I'm trying to access shipments for all organizations but two.
This code works but only returns shipments for the FIRST organization that's returned by my .where.not calls. I would like to join the shipments for all Organizations returned by my .where.not calls.
Organization.where.not(name: "Admin Org").where.not(name: "Test Organization").first.shipments
Thanks!
We need to do the query on Shipment model to fetch all the shipments of all the organizations except those two, which we will filter out using where.not caluse.
So the query would be like this:
#shipments = Shipment.joins(:organization).where.not(organization: {name: "Admin Org"}).where.not(organization: {name: "Test Organization"})
And a bit cleaner:
#shipments = Shipment.joins(:organization).where.not(organization: {name: ["Admin Org", "Test Organization"]})
I ended up creating an array and using two .each blocks to dump shipments into it:
array = []
Organization.where.not(name: ["Admin Org", "Test Organization"]).each { |x| x.shipments.each { |z| array << z } }
Related
I am trying to join tables to get an object.
I have these models:
class Company < ApplicationRecord
has_many :users
end
class Claim < ApplicationRecord
has_many :uploads, dependent: :destroy
validates :number, uniqueness: true
belongs_to :user, optional: true
end
class User < ApplicationRecord
belongs_to :company
has_many :claims
end
Basically I want to select all claims that belong to users that belong to a company.
Somethings I have tried:
(This works but is terrible and not the rails way)
#claims = []
#company = Company.find(params[:id])
#users = #company.users
#users.each do |u|
u.claims.each do |c|
#claims.push(c)
end
end
#claims = #claims.sort_by(&:created_at)
if #claims.count > 10
#claims.shift(#claims.count - 10)
end
#claims = #claims.reverse
This is close but doesn't have all the claim data because its of the user:
#claims = User.joins(:claims, :company).where("companies.id = users.company_id").where("claims.user_id = users.id").where(company_id: params[:id]).order("created_at DESC").limit(10)
I tried this but keep getting an error:
#claims = Claim.joins(:user, :company).where("companies.id = users.company_id").where("claims.user_id = users.id").where(company_id: params[:id]).order("created_at DESC").limit(10)
error: ActiveRecord::ConfigurationError (Can't join 'Claim' to association named 'company'; perhaps you misspelled it?)
Any ideas what I should do or change?
Based on your relations, you should use
Claim.joins(user: :company)
Because the Company is accessible through the relation Claim <> User.
If you wanted to join/preload/include/eager load another relation, let's say if Claim belongs_to :insurance_company, then you would add it like this:
Claim.joins(:insurance_company, user: :company)
Similar questions:
Join multiple tables with active records
Rails 4 scope to find parents with no children
That being said, if you want to
select all claims that belong to users that belong to a company
Then you can do the following:
Claim
.joins(:user) # no need to join on company because company_id is already on users
.where(company_id: params[:id])
.order(claims: { created_at: :desc })
.limit(10)
Tada!
Goal: I would like to include all of a customers medical conditions as an array in the result of a customer.
for:
cust = Customer.includes(:conditions).find(1)
expected result:
#<Customer id: 1, first_name: "John", last_name: "Doe", conditions [...]>
actual result:
#<Customer id: 1, first_name: "John", last_name: "Doe">
code:
I have 2 classes and a 3rd join class (ConditionsCustomer).
class Customer < ApplicationRecord
has_many :conditions_customers
has_many :conditions, through: :conditions_customers
end
#join table. Contains 2 foreign_keys (customer_id, condition_id)
class ConditionsCustomer < ApplicationRecord
belongs_to :customer
belongs_to :condition
end
class Condition < ApplicationRecord
has_many :conditions_customers
has_many :customers, through: :conditions_customers
end
What's interesting is that I see 3 select queries getting fired (customer, join table and medical conditions table) so I know the includes is somewhat working but unfortunately customer returns without the medical conditions.
I've also tried using a join but I get an array of same customer over and over again.
Is there an easy way to do this with ActiveRecord? I would prefer not having to merge the record manually.
Not really possible via active record, as json offers some cool possibilities :
render json: customers,
include: {
conditions: {
only: [:attr1, :attr2], # filter returned fields
methods: [:meth1, :meth2] # if you need model methods
},
another_joined_model: {
except: [:password] # to exclude specific fields
}
}
I have models like below
Customer.rb
has_many :appointments
has_many :addresses
has_many :contacts
Address.rb
belongs_to :customer
Contact.rb
belongs_to :customer
Appointment.rb
belongs_to :customer
I have defined API's to return customers like below but with one extra attribute i.e appointment_id.
customers: [
{
appointment_id: 'xxxxxxx'
..
..
..
addresses: [{...}, {...}]
contacts: [{...},{...}]
},
{
..
},
.....
]
The above api is defined in a way that I pass #customers (which is array of customers along with their nested objects address, contacts). Problem is How should write active record query to return so so data.
Current Approach:
// I got list of appointment id's and I should return corresponding customers data as shown in above api.
cust_ids = Appointment.where(blah blah blah).pluck(:customer_id)
#customers = Customer.where(appointment_id: cust_ids).includes(:addresses, :contacts)
What I want?
My above approach doesnt have appointment_id in #customers object. How should I get it? Do I need to join table
along with includes. ??
Add inverse of to association definitions to avoid n+1 during preload
# customer.rb
has_many :appointments, inverse_of: :customer
# appointment
belongs_to :customer, inverse_of: :appointment
Now you can fetch your appointments from the DB and construct JSON
# in the controller
appointments = Appointment.where(blah blah blah)
.preload(customer: [:contacts, :addresses])
customers = appointments.map do |appointment|
appointment.customer
.as_json(include: [:contacts, :addresses])
.merge(appointment_id: appointment.id)
end
render json: { customers: customers }
Here is what I can think of
appointment_ids = Appointment.where(blah blah blah).pluck(:id)
customers = Customer.includes(:addresses, :contacts, :appointments).where(appointments: { id: appointment_ids })
Now when you will write
customers.first.appointments you will only get those appointments which satisfy the first condition.
And According to your say, it will have only one appointment per customer per day.
So you can do customers.first.appointments.first.id
Use select in the query:
cust_ids = Appointment.where(blah blah blah).pluck(:customer_id)
#customers = Customer.where(appointment_id: cust_ids).includes(:addresses, :contacts).select("customers.*")
Model:
class User < ActiveRecord::Base
has_many :requests, class_name: 'Story', foreign_key: 'requester_id'
has_many :ownerships, class_name: 'Story', foreign_key: 'owner_id'
def stories
requests | ownerships
end
end
In this case the method stories will return an array of uniq objects as I want. But I'll need to use something like User.first.stories.where("title = 'foo'") that returns an error, because it's an array, not a relation.
So what can I do to get this same results through relation allowing to use with Arel?
PS.: Im on Rails 3.1.rc6
class User < ActiveRecord::Base
def stories
Story.where "(owner_id = :id) OR (requester_id = :id)", :id => id
end
end
or this could be written even nicer if you use squeel
def stories
Story.where { (owner_id == my{id}) | (requester_id == my{id}) }
end
Only a scope returns a relation. Transforming the method as LOJ scope should help I guess.
scope :stories, select('stories.*').joins('LEFT OUTER JOIN stories ON
users.id = stories.requester_id LEFT OUTER JOIN stories ON users.id = stories.owner_id')
I am using Rails 3 beta 4.
I have the following models:
class Player < ActiveRecord::Base
has_many :players_items, :dependent => :destroy
has_many :items, :through => :players_items
end
class PlayersItem < ActiveRecord::Base
belongs_to :player
belongs_to :item
end
class Item < ActiveRecord::Base
has_many :players_items, :dependent => :destroy
has_many :players, :through => :players_items
end
In the players_controller
def items
#player = Player.find(params[:id])
#player_items = #player.items
end
I have the following attributes
--Items Model--
Item_id:Integer
Name:String
Cost:Integer
Description:Text
--PlayersItem Model--
Item_id:Integer
Player_id:Integer
Total:Integer
Traded:Integer
I am trying to print out all the items associated with a player and for each item print out the "Name", "Cost", "Description", "Total", and "Traded" values.
When I call #player_items in the items.html.erb, I can only access the attributes associated with the Item Model and not any of the attributes associated with PlayersItem model.
I am trying to access the attributes from both the items model and players_items model in the same "call" similar to SQL Join Statement like this
SELECT * FROM players_items INNER JOIN items ON players_items.item_id=items.id
WHERE players_items.player_id = "#player"
Is this possible?
#player = Player.order("created_at").last
#player.players_items.each do |item|
puts "#{item.player}: #{item.description} cost:#{item.cost}"
end
Has many through is a little weird. Think of it as a model whose name should (ideally) be descriptive of the relationship between the two other models. So maybe if equipment is being distributed to the players you could call the join model distributions or loans or something. The players_items is the naming convention for join tables which aren't going to be addressed directly.
I hope that helps!
Used in the controller
#player = Player.find(params[:id], :include => [:items,:players_items])
And in the view
#player.players_items.each do |player|
puts "#{player.name}: #{player.player.item.description} cost:#{player.item.cost}"
end