Ruby on rails querying with join and condition statement - ruby-on-rails

I need to query joining tables without using the primary key(id).
class User < ActiveRecord::Base
has_one :participant
end
class Participant < ActiveRecord::Base
belongs_to :user
end
The User has 'id' and 'name'.
The Participant has 'user_id' which is User.id
I am trying to find the Participant.id by querying with User.name
What I have tried is,
participant_id = Participant.all :joins => :users, :conditions => {:name => "Susie"}

If you're just looking for a specific user's participant id, you could just go:
User.find_by_name("Susie").participant.id
Since your user has a has_one relation to Participant(which belongs to it -- so basically a one-to-one) you can just go call participant on user. ActiveRecord takes care of the join magicks for you

Try the following:
class User < ActiveRecord::Base
has_one :participant
end
class Participant < ActiveRecord::Base
belongs_to :user
scope :foo, lambda {|name|
joins(:users).
where("name = ?", name)
}
end
If you're taking user input you're going to want to probably fix joins so it uses sanitize_sql_array. See here also for some query goodness

Related

Most efficient way to pull a specific record from an ActiveRecord collection

In my database, Account has many Contacts.
class Account < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :account
end
Contacts has a field called primary_contact, which denotes the record as the primary. In a situation where I need to pull all contacts for an account, and list the primary contact separately, is there an efficient way to pull this primary record out with ActiveRecord, or should I just identify the correct record in the collection that it returns by looking at the values of that field manually?
Ideally I would like to be able to do something like account.primary_contact or even contacts.primary to identify this, but it's not necessary.
you can add a has_one association
class Account < ActiveRecord::Base
has_many :contacts
has_one :primary_contact, class_name: 'Contact', conditions: { primary_contact: true }
end
UPDATE: rails 4 syntax would be
has_one :primary_contact, -> { where(primary_contact: true) }, class_name: 'Contact'
class Contact < ActiveRecord::Base
belongs_to :account
scope :primary, where( primary_contact: true )
end
Then if you have an account:
account.contacts.primary
should give you the primary contacts.

Optimize ActiveRecord query

I have 2 tables in database: cars and domains.
One car can have many domains and one domain can have many cars.
In my project three models:
class Car < ActiveRecord::Base
has_many :cars_domains
has_many :domains, :through => :cars_domains
...
class Domain < ActiveRecord::Base
has_many :cars_domains
has_many :cars, :through => :cars_domains
...
class CarsDomain < ActiveRecord::Base
belongs_to :car
belongs_to :domain
end
I want to see cars which without domain:
#cars = Car.find(:all, :conditions => ['id not in(select car_id from cars_domains where domain_id = ?)', params[:domain_id]])
It's work, but I think it's very difficult. Maybe possible to do it more simple?
Tried this in a quick app I created:
domain = Domain.find(params[:domain_id])
Car.includes(:cars_domain).where('cars_domain.domain_id <> ?', domain.id)
The reason I query the domain object is because I'm always weary about passing a value from the request headers as a query parameter in SQL.

Rails 3 Multiple Foreign Keys

Im writing an app that has a user model, and the users in this model can be two different user types.
user.rb
class User < ActiveRecord::Base
has_many :transactions
has_many :transaction_details, :through => :transactions
has_many :renters, :class_name => "Transactions"
end
transaction.rb
class Transaction < ActiveRecord::Base
has_many :transaction_details
belongs_to :user
belongs_to :renter, :class_name => "User"
end
transaction_detail.rb
class TransactionDetail < ActiveRecord::Base
belongs_to :transaction
belongs_to :inventory
scope :all_open, where("transaction_details.checked_in_at is null")
scope :all_closed, where("transaction_details.checked_in_at is not null")
end
Basically a user could be a renter, or the person checking the item out. Once I have a transaction, I can call:
#transaction.renter.first_name # receive the first name of the renter from the renter table
#transaction.user.first_name # receive the first name of user who performed the transaction
This is perfect and works as I explected. For the life of me, I can not figure out how to get the scope to work when called through a user:
# trying to perform the scrope "all_open", limted to the current user record, but I cant get it to use the
# renter_id column instead of the user_id column
u.transaction_details.all_open
is this possible to have a scrope look up by the second forien_key instead of user_id?
Short answer - Yes. This is very possible.
You need to mention the foriegn key being used in the reverse association definition.
In users.rb:
has_many :rents, :class_name => "Transactions", :foreign_key => "renter_id"
This will allow you to write:
User.find(5).rents # array of transactions where user was renter
If you want to call the transaction_details directly, then once again you would need to specify another association in user.rb:
has_many :rent_transaction_details, :through => :rents, :source => "TranactionDetail"
Which would allow you to call:
User.find(5).rent_transaction_details.all_open

Rails: Pulling results for a polymorphic association

I have a the following polymorphic association set up:
class Favorite < ActiveRecord::Base
belongs_to :favoritable, :polymorphic => true
belongs_to :user
end
class Photo < ActiveRecord::Base
has_many :favorites, :as => :favoritable
belongs_to :user
end
What I ultimately want to do is pull all the photos a specific user has favorited.
How would I make that happen?
You could use the Active Record Query Interface for this:
Photo.joins(:favorites).where("favorites.user_id = ?", user_id)
This will return an Array of Photo objects (along with joined fields from Favorite) that a specific user has favorited. You'll have to pass in the user_id to this call.

Using default_scope in a model, to filter by the correct instanceID

I have two tables:
books (id, name, desc, instance_id)
instances (id, domain)
A user should ONLY be able to see data that is assigned to their instance_id in records...
For the books, model, to accomplish this, I'm thinking about using a default scope.. Something like:
class Books < ActiveRecord::Base
attr_accessible :name, :description
belongs_to :user
default_scope :order => 'books.created_at DESC'
AND books.instance_id == current.user.instance_id
end
Any thoughts on that idea? Also how can I write that 2nd to last line for Rails 3? 'AND books.instance_id == current.user.instance_id'
Thanks
It's not a good idea to access the current user inside the model. I would implement this as follows:
class Instance < ActiveRecord::Base
has_many :users
has_many :books
end
class User < ActiveRecord::Base
belongs_to :instance
has_many :books, :order => "created_at DESC"
has_many :instance_books, :through => :instance, :source => :books,
:order => "created_at DESC"
end
class Book < ActiveRecord::Base
belongs_to :user
belongs_to :instance
end
List of Books associated with the user instance:
current_user.instance_books
List of Books created by the user:
current_user.books
Creating a new book:
current_user.books.create(:instance => current_user.instance, ..)
Note:
Your book creation syntax is wrong. The build method takes hash as parameter. You are passing two arguments instead of one.
user.books.build(params[:book].merge(:instance => current_user.instance}))
OR
user.books.build(params[:book].merge(:instance_id => current_user.instance_id}))

Resources