Ruby Gem ActiveRecord find method with multiple conditions - ruby-on-rails

I'm building a Sinatra application using three database's tables: user, post and like.
I'd want to run a query that will find an entry in the like table like so:
FIND in like WHERE user_id == params[:user_id] AND post_id == params[:post_id]
(for one condition I'll be using: Like.find_by_user_id(params[:user_id]))
My question is:
How to run a find query with multiple conditions using the ActiveRecord Gem?

Use where:
Like.where('user_id = ? AND post_id = ?', params[:user_id], params[:post_id])
or
Like.where('user_id = :user_id AND post_id = :post_id', params)
Is important to keep in mind that the paremeters of the where need to be converted to the expected type for example params[:post_id].to_i

Similar to find_by_user_id for user_id column you can combine multiple column names and get a dynamic finder find_by_user_id_and_post_id:
Like.find_by_user_id_and_post_id(params[:user_id], params[:post_id])
When there are more than "bearable" columns in the find_by_ finder, you could use where and supply the condition as follows:
Like.where(user_id: params[:user_id], post_id: params[:post_id])

Like.find_by_user_id(params[:user_id]) - this syntax is deprecated in ActiveRecord 4.
Instead try using where method of ActiveRecord query interface, to pass array conditions. Example:
Like.where("user_id = ? AND post_id = ?", params[:user_id], params[:post_id])

If you are expecting one record to be the result:
To replace find_by_whatever you can use find_by(whatever) for example User.find_by(username:"UsernameIsMyUsername",password:"Mypassword"). You should use find_by if there is only one record that you expect to match your search.
If you are expecting more than one record to be the result:
If you expect more than one you should use where with where(username:"MyUsername",password:"Password"). This will return all the resulting records in an array.

Related

Rails How do I find case insensitive values that are not already associated to the user?

Newbie Rails developer here so please bare with me.
I have a table called Ingredients where it contains a title field and an association to a User. A user can have many ingredients.
I want to query the database to get the ingredients that are not already available to a User.
I tried doing something like this with Rails:
#ingredients = current_user.ingredients
#community_ingredients = Ingredient.all.excluding(#ingredients).pluck(:title, :id)
But the problem is that this still returns values that are the same & only the case is different.
How can I achieve this outcome?
Try following queries.
#community_ingredients = Ingredient.includes(:user).where("users.user_id = ?", current_user.id).where(users: { id: nil } ).pluck(:title, :id)
OR
Ingredient.includes(:user).where("users.user_id = ?", current_user.id).where(ingredients: {user_id: nil } ).pluck(:title, :id)
OR
Ingredient.includes(:user).where("users.user_id = ?", current_user.id).where(users: { ingredient_id: nil } ).pluck(:title, :id)
Choose right query based on your association and feel free to suggest me so I can remove the extra one.
Most probably the first or second query will work, I strongly feel the third might not be the case.
Let's say this one is not working for you and you want to have solution based on your architecture.
#ingredients = current_user.ingredients.pluck(:title)
#community_ingredients = Ingredient.where.not("lower(title) IN (?)", #ingredients.map(&:downcase)).pluck(:title, :id)
So basically we need to convert both column value and the matching list in same case.
So we have converted to downcase.
here is how it looks in my local system, just make sure it's working that way.

How to show all departments where school name = x?

Upon the creation of a department, users have the option to add the name of a school. On the show page of the school, I want to show all the departments with the school of that name.
My school controller's show action looks like this:
def show
#department = Department.where(:school == 'university of connecticut')
end
This obviously isn't working. What is the correct syntax for this?
Either if these should give you the expected results:
#department = Department.where(school: 'university of connecticut').first
or
#department = Department.where('school = ?', 'university of connecticut').first
where takes either a hash or a SQL statement. Note that in the first example, we're using the shortcut hash method when using a symbol symbol: value, which is equivalent to :symbol => value
Also, keep in mind that where returns an ActiveRecord::Relation object, not an ActiveRecord object. You'll need to add .first or another form of .find if you wish to receive an ActiveRecord object directly.
You're close:
Department.where(school: 'university of connecticut').first
i.e. normal hash syntax.

simple Or statement

I am trying to do a simple or statement in a controller
This generates one set of trips that I am interested in displaying and is working fine.
#trips = Trip.where(:userid => #friends)
However, i would like to add another set of trips; trips whose userid == current_user.id
#trips = Trip.where(:userid => current_user.id)
Trying to combine these two i tried...
#trips = Trip.where(:conditions => ['userid= ? OR userid=?', #friends, current_user.id])
Any idea where the bust is? Thanks in advance.
Simply pass an array to get the equivalent of the SQL WHERE ... IN clause.
Trip.where(userid: [#friends, current_user.id])
See the ActiveRecord Rails Guide, 2.3.3 Subset Conditions
Is #friends an array? ActiveRecord will convert your where statement into a SQL IN clause when you generate it with the hash syntax. When you build your OR statement in raw SQL, you need to do the IN manually.
#trips = Trip.where('userid IN ? OR userid = ?', #friends, current_user.id)
Also, your column is called userid ? Typicaly it would be called user_id - is this a typo or do you just have an abnormal database?

List reference columns of a active record model

using Rails 3.2, there is a way to find out if a column is a reference column to other model?
I don't want to rely in "_id" string search in the name.
thanks.
UPDATE:
I need to iterate over all columns and made a special treatment in references columns, something like:
result = Hash.new
self.attribute_names.each do |name|
if self[name]
result[name] = self[name]
if name is reference column
insert xxx_description (from the other model) in hash.
end
end
end
I will return this hash as json to client.
{name: 'joseph', sector_id: 2, sector_name: 'backend'...}
Where sector_name, is person.sector.name...
thanks.
alternative method if you don't know the name of the association :
Post.reflect_on_all_associations(:belongs_to).map &:foreign_key
# => ['author_id','category_id']
See http://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html
Post.reflections[:comments].primary_key_name # => "message_id"
How to get activerecord associations via reflection

rails where() sql query on array

I'll explain this as best as possible. I have a query on user posts:
#selected_posts = Posts.where(:category => "Baseball")
I would like to write the following statement. Here it is in pseudo terms:
User.where(user has a post in #selected_posts)
Keep in mind that I have a many to many relationship setup so post.user is usable.
Any ideas?
/EDIT
#posts_matches = User.includes(#selected_posts).map{ |user|
[user.company_name, user.posts.count, user.username]
}.sort
Basically, I need the above to work so that it uses the users that HAVE posts in selected_posts and not EVERY user we have in our database.
Try this:
user.posts.where("posts.category = ?", "Baseball")
Edit 1:
user.posts.where("posts.id IN (?)", #selected_posts)
Edit 2:
User.select("users.company_name, count(posts.id) userpost_count, user.username").
joins(:posts).
where("posts.id IN (?)", #selected_posts).
order("users.company_name, userpost_count, user.username")
Just use the following:
User.find(#selected_posts.map(&:user_id).uniq)
This takes the user ids from all the selected posts, turns them into an array, and removes any duplicates. Passing an array to user will just find all the users with matching ids. Problem solved.
To combine this with what you showed in your question, you could write:
#posts_matches = User.find(#selected_posts.map(&:user_id).uniq).map{ |user|
[user.company_name, user.posts.size, user.username]
}
Use size to count a relation instead of count because Rails caches the size method and automatically won't look it up more than once. This is better for performance.
Not sure what you were trying to accomplish with Array#sort at the end of your query, but you could always do something like:
#users_with_posts_in_selected = User.find(#selected_posts.map(&:user_id).uniq).order('username DESC')
I don't understand your question but you can pass an array to the where method like this:
where(:id => #selected_posts.map(&:id))
and it will create a SQL query like WHERE id IN (1,2,3,4)
By virtue of your associations your selected posts already have the users:
#selected_posts = Posts.where("posts.category =?", "Baseball")
#users = #selected_posts.collect(&:user);
You'll probably want to remove duplicate users from #users.

Resources