Get all records that have an associated record - ruby-on-rails

A Post has_many Tags. Each tag record has a name, like "fashion" or "business".
How can I get all posts that have the tag with name "fashion"?
# Get all posts
#posts = Post.all
# Get the filter tag
#filter_tag = Tag.find_by_name(params[:filter_name])
Ok so now we have all posts, and now I just want the #posts that have the #filter_tag. What should I do?
I could loop through each post, and check if it has the filter tag. If so, add it to an array. I'm sure Rails ActiveRecord has a better method though.

If you have your associations set up correctly then
#filter_tag_posts = #filter_tag.posts

Related

How to access variables in model

I am trying to get access to a property contained inside my user object.
My user model has_many: posts. In the controller how would i gain access to these posts? Would i create a method in the model?
def posts
#posts = Post.find(User_id: params[:id])
end
or can i directly access the posts for the user. User.posts Since i am currently residing in the controller, is the controller aware of the currently selected model? Or do i have to pull the information again?
You can query the database for all the posts with a specific user_id, like this:
#posts = Post.where(user_id: params[:id])
Alternatively, you can find the user first and then fetch all posts associated with that user, like this:
user = User.find(params[:id])
#posts = user.posts
Assuming your id in params is the id of your user, you can use user = User.find(params[:id]) to get the user and #posts = user.posts to get all the posts of this user.
So, it is not about where you are, It is about what you are calling.
I'm sure you are familiar with relationships...
When you have relationships, it means that you can get to one relation from the other through whatever association exists between them.
If I am my father's son, then you can get me directly by checking my father's children. ( you don't necessarily have to get all children in the village first )
So, bringing all my story above together, with the association between your Post and User, you can always call user.posts (user being an instance of User) and post.user ( with post being an instance of Post)
The Ruby on Rails guides have a section on associations, which is what you want. It's here: http://guides.rubyonrails.org/association_basics.html
In a nutshell, because you have added an association in your user model to a number of post records, Rails will build a helper method in your user model called posts. You can use that to access all the posts associated with that user.
When you create a post, the post record needs to have a column called user_id. This will provide the 'physical' link between the user and post models. You can access the posts from a user like so:
user.posts each do |post|
# do something with post.content
end
To get posts that match some criteria in the posts collection you can query like this:
posts = user.posts.where(:something => 'matches criteria')
If you know there's only one post that matches the criteria, you can do this:
post = user.posts.where(:something => 'matches criteria').first
The post model also needs a belongs_to :user association. (The belongs_to will generate a helper method called user in the post model which you can then use to access the user record from the post.) For example:
user_email = post.user.email
The user record does not require a post_id column since Rails knows that user.post refers to the post table and automagically generates a query using user_id.
Anyway, the guide I linked to above will give you all the information you need and more too.

Filter index view by related model attribute in rails

I have a rails 4 that has a Post model related to a Tag model by an habtm relation.
Tags have a name field and a category field. Multiple tags can have the same category.
I need a view that displays only posts that have at least one tag belonging to the "foo" category. Foo is static and will always remain "foo".
I've been able to make it work using this code in my posts controller:
def myview
ids = []
Tag.where(category: 'foo').each do |tag|
tag.posts.each do |post|
ids << post.id
end
end
#posts = Post.where(id: ids).all
end
Despite working my code looks really ugly to read.
I'm sure rails provides a way like "#posts = Post.where tag categories include 'foo'.all" but I cannot figure out a way. I'm sure I'm missing something very obvoius.
Post.joins(:tags).where('tags.category = ?', "foo").all
The answer in the comment is where, for example, you didn't want to query by the tag but maybe wanted to include some information relating to the tag in your view. By using includes, you will avoid the N+1 problem.

Rails has_and_belongs_to_many query

I have the following database schema in my rails 4 application
Users >---Tags_users---< Tags >---Posts_tags---< Posts
given the currently logged in user, what is the best way for me to get all of the posts (from all users) that match there tags the tags that they are interested in.
You can pass an array to Model#where to get an array of posts with the choosed criteria.
def show_by_tags
#posts = Post.all
array_of_tags.each do |tag|
#posts.where(tag_name: tag)
end
end

ActiveRecord help: Where tags include

I cant seem to find a way to do this. Some guidance would be great!
I'm building a blog like site with posts and posts contain tags. The tags and posts are held together by a join table. I can access them via post.tags.
Im trying to put together a search to display all posts containing a certain tag.
After trying for awhile this is the best I came up with:
def tag
tag = Tag.find_by_title(params[:id])
p = Post.page(params[:page]).per_page(7).all
#posts = Array.new
p.each do |p|
if p.tags.include? (tag)
#posts << p
end
end
This works all except the pagination. Im thinking there has got to be a simple where clause to simplify this?
Thanks!
Edit:
Here is my join table
The next method should return the array of post tagged with the tag :
#posts = Post.includes(:tags).where('tags.id' => tag.id)
You just have to keep the first line of your method and add the line above after.
Notice that to make it working you should have defined the relationships between your post and tag in your model with an has_and_belongs_to_many.

Rails - FriendlyId and Conditions

I have a model posts, which belongs_to category (which uses friendly_id). Now i want to list all Posts in an Category. To get the index page i want to use a link like: http://mysite/posts/category/_category_slug_, for that i made the following route:
match 'posts/category/:category/' => 'posts#index'
And in my post controller i got:
def index
if params[:category]
#posts = Post.all(:joins => :category, :conditions => {"categories.cached_slug" => params[:category]})
else
#posts = Post.all.reverse
end
...
It works like it should, but i dont think its the friedndly_id way to do it.
Is there a better way to achive this? thanks for your help.
FriendlyId adds the ability to do a find on a model using the slug, and is smart enough to check the cached_slug column first.
You can achieve the same result by performing a find on the Category model first then getting all the posts.
This assumes there is a has_many and belongs_to association in place with the referencing ID columns (or HABTM)
def index
if params[:category]
#posts = Category.find(params[:category]).posts
else
#posts = Post.all.reverse
end
...
Since you're passing in a category param (being friendly_id), it makes sense to reference it via the Category model.
-- more info added --
ALSO: Historical finds will still work ..
So, if you have generated a new slug by renaming a category, the old url will behave correctly (great if you're avoiding 404's)

Resources