Using finders to query a referenced model in Rails 3? - ruby-on-rails-3

I have a model called Person that has_one Address. Person has fields like first_name and last_name; Address has postal_code, state, and so on.
I know how to use finders to find all people with a certain name; that's Person.find_by_last_name("Smith"). But how do I find all people where:
their first_name is "Bob"; and
their last_name is "Smith"; and
who have addresses with a city of 'Foobar'; and
who have addresses with a postal_code of '12345'

When you're looking for exact values, you can pass a hash of the values you'd like to match to where. Each referenced model is its own nested hash, as in the example below:
Person.
where(:first_name => 'Bob').
where(:last_name => 'Smith').
where(:address => { :postal_code => '12345' }). # queries associated Address
where(:address => { :city => 'Foobar' }) # queries associated Address

Related

Rails/SQL: Using an array as a search parameter

In an ecommerce shop application I would like to retrieve all orders that match a first_name that was entered via a search form and where paid == true. The search form submits the search term via params Parameters: {"utf8"=>"✓", "search"=>"john", "commit"=>"Search"}. In the controller
#users = User.search(params[:search]) #returns all users with the matching first_name, e.g. 'john'
#order = Order.where('user_id = ? AND paid = ?', #users.ids, true )
The query in #order works just fine, if only one user is returned, e.g. only one user is named john. But if multiple users are named John, multiple user ids are returned and the error message ActiveRecord::StatementInvalid is returned. My understanding is that the query stops working once `#users.ids is an array with more than one value.
How do I structure the following query: for each user_id return all orders (user.orders) where paid equals true.
Models
user.rb
has_many :orders
order.rb
belongs_to :users
There are various ways to go about this.
You can use a JOIN as Nic Nilov suggests but this can be difficult if your #users query is built using scopes and you don't want to manually inline those scopes.
You could also use a subquery since ActiveRecord in Rails4 is smart enough do The Right Thing when you use a relation in a where, you just have to use the hash form of where:
#users = User.search(params[:search])
# #users should be a User::ActiveRecord_Relation now.
#orders = Order.where(:user_id => #users, :paid => true)
This will end up with SQL like:
select *
from orders
where paid = 't'
and user_id in (
select id
from users
where /* whatever `search` does... */
)
The advantage here is that you don't need to know what User.search does as long as it is returning an ActiveRecord relation.
If your #users is actually an array (of ids or whole User instances) then you'd do it exactly the same way:
# Suppose #users is an array of Users or an array of User ids...
#orders = Order.where(:user_id => #users, :paid => true)
and ActiveRecord will figure out what to do with your #users array without you having to do anything extra.
Instead of two queries, you should use a nested query with a WHERE IN clause
SELECT * from Order WHERE user_id IN (SELECT user_id FROM users WHERE first_name LIKE ?) AND paid = true
This should do:
Order.joins(:user).where(users: { name: params[:search] }, paid: true)
It generates a single query with an INNER JOIN:
SELECT "orders".*
FROM "orders"
INNER JOIN "users" ON "users"."id" = "orders"."user_id"
WHERE "users"."name" = 'Test User' AND "orders"."paid" = 't'

How to get same Columns from different tables

I have 3 tables
task (Id,text,Contact_Id)
users(Id,name)
company(id,name)
and 2 junction tables
task_users (task_id,user_id)
task_companies (task_id,company_id)
note: contact_id may be refer to users table or company
How can I get task id, task text, contact name in one Criteria
This's example with QueryOver, but it almost like ICriteria.
Contact contact = null;
mappingSession.QueryOver<Task>()
.JoinAlias(() => task.Contact, () => contact)
.SelectList(list => list
.SelectGroup(task => task.Id)
.Select(task => task.Text)
.Select(() => contact.Name))
.TransformUsing(Transformers.DistinctRootEntity)
.List();
Other is a mapping. You can make base entity "Contact" and extend from it User and Company.

ActiveRecord find with include

Let's say that Person has_many Addresses, and with this query I can go through the loop and use addresses for that peoples.
#people = Person.find(:all, :include => :addresses)
But, I want to include ONLY addresses where the user_id = 1 for example.
How to build query to do that?
P.S. New to RoR
#people = Person.find(:all, :include => :addresses, :conditions => ['user_id=?',params[:user_id]])
Make note that when you include you can only have one column of each or rails will give you an error about ambiguous find conditions.

Rails problems with Join search

I am developing a small user application in Rails 3 and is stuck on a search feature. I got a table called Profile which holds Firstname and Lastname. When searching this table I use:
Profile.find_all_by_firstname(params[:keyword])
The thing is that I want the user to be able to search a table that holds contacts (profile_id and friend_id only) but I want them to be able to seach by name here too. How is this done?
For example:
John searches for the name Ann which is a contact of his. Since the Contact table does not store names the search must include the Profile table in the query. How can I do this?
UPDATE
This join query fetches everyone not only the contacts, can anyone spot a problem with it?
Profile.find_all_by_firstname(params[:keyword],
:select => "firstname, lastname, user_id",
:joins => "left outer join contacts on profiles.id = contacts.profile_id")
Profile.find_all_by_firstname(params[:keyword],
:select => "firstname, lastname, user_id",
:joins => "left outer join contacts on profiles.id = contacts.profile_id")
this query fetches everyone because you serch only by the firstname If you whant select contacts that are friends of the particular user firstly you must have his id Then you should add this to your conditions
current_user = Profile.first
Profile.find(:all,
:conditions => ["profiles.firstname = ? AND contacts.friend_id = ?", params[:keyword], current_user.id],
:joins => :contacts)
or make join conditional
current_user = Profile.first
Profile.find_all_by_firstname(params[:keyword],
:select => "firstname, lastname, user_id",
:joins => "INNER JOIN contacts on (profiles.id = contacts.profile_id AND contacts.friend_id = #{current_user.id})")
but I'm not quite sure about syntax

Map table inheritance as a one-to-one relationship with NHibernate

I have a database that has a one-to-one relationship modeled between a Person and a Address (that uses person id). However, I cannot find a way to make the map using NHibernate.
My table structure is the following:
PersonTable
PersonId
PersonName
PersonAge
AddressTable
PersonId
CountryName
StreetName
StateName
And I would like to have something like this as the final class:
PersonClass
int Id
string Name
int Age
Address HomeAddress
AddressClass
string Street
string Country
string State
Person Owner
I tried with HasOne relationship but I couldn´t reuse PersonId as Address Identifier.
Thanks!
Edit: I forgot to mention that I´m using FluentNHibernate so both fluent mapping and XML will be fine.
The problem is that your database schema does not represent a "Has One" relationship between Person and Address. It represents a "Has Many" relationship; You may be artificially limiting it to be one address per person, but that doesn't change the fact that the model is multiple addresses per person.
To get a "Has One" relationship, you would put the AddressID on the the PersonTable.
I did it using Id().GeneratedBy.Foreign() in Address class map referencing it to the Person´s ID and it worked.
Thanks!
I would map it as a component of Person. In the person ClassMap add the following:
Component(x => x.Address, m =>
{
m.Map(x => x.Street, "Street");
m.Map(x => x.State, "State");
// more here
});
Cheers