Reputation: 33
I am building a system for category search. At that time, the following errors are occurring in the current system.
Couldn't find all Post with 'id': (false, true) (found 1 results, but was looking for 2).
Controllers
def category
@category = params[:category_name]
@posts=Post.find(PostCategory.group(:post_id).pluck(:@category))
#↑The error point.
end
routes
get '/category/:category_name', to: 'pages#category'
Views
<li><a href="category/casual">casual</a></li>
<li><a href="category/natural">natural</a></li>
<li><a href="category/clean">clean</a></li>
<li><a href="category/rock">rock</a></li>
<li><a href="category/formal">formal</a></li>
<li><a href="category/street">street</a></li>
<li><a href="category/hip_hop">hip_hop</a></li>
<li><a href="category/sports">sports</a></li>
<li><a href="category/outdoors">outdoors</a></li>
<li><a href="category/surf">surf</a></li>
Relationship of models
belongs_to :post
has_one :post_category
accepts_nested_attributes_for :post_category
PostCategory table
create_table "post_categories", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "casual", default: false, null: false
t.boolean "natural", default: false, null: false
t.boolean "clean", default: false, null: false
t.boolean "rock", default: false, null: false
t.boolean "formal", default: false, null: false
t.boolean "street", default: false, null: false
t.boolean "hip_hop", default: false, null: false
t.boolean "sports", default: false, null: false
t.boolean "outdoors", default: false, null: false
t.boolean "surf", default: false, null: false
t.integer "post_id"
t.index ["post_id"], name: "index_post_categories_on_post_id"
end
Example.
I want to find a column where category_name params(casual)
and PostCategory column(casual)
are the same, and from there, find only the ones that are true, and retrieve all the records of Post
whose post_id
corresponds to PostCategory column(casual, only true)
and reflect them in the view.
Thank you.
Upvotes: 0
Views: 238
Reputation: 14295
First, there's a problem in your category
method where it says :@category
. That would probably need to say @category
(without the colon), so that the method body's second line reads:
@posts=Post.find(PostCategory.group(:post_id).pluck(@category))
^
That aside, it seems that you're trying to fetch all posts that belong to a certain category. What you're doing right now won't work because your query returns an array of booleans, and then you use booleans to look up posts. But you'd need ids to look up posts because you can't pass booleans to Post.find
.
Why not just do (not tested):
@posts = Post.find(PostCategory.where(@category => true).pluck(:post_id))
or, in a single query (not tested either):
@posts = Post.joins(:post_category).where("post_categories.#{@category}" => true)
But for that last one you may need to check the @category
variable against a whitelist to avoid injections. EDIT: As Max suggests in the comments, you may want to change the where clause to where( post_categories: { @category => true })
to avoid injections.
Upvotes: 1
Reputation: 102343
A better solution which doesn't require you to modify the database to add categories would be to just setup a more sane normalization table / join table setup:
# rails g model category name:string:uniq
class Category < ApplicationRecord
has_many :categorizations
has_many :posts, through: :categorizations
validates :name,
uniqueness: true,
presence: true
end
# rails g model categorization post:belongs_to category:belongs_to
class Categorization < ApplicationRecord
belongs_to :category
belongs_to :post
validates :post_id,
uniqueness: { scope: :category_id }
end
class Post < ApplicationRecord
has_many :categorizations
has_many :categories, through: :categorizations
end
The Rails to handle this would either to handle this on the categories#show action (or with a nested route):
resources :categories
class CategoriesController < ApplicationController
def show
@category = Category.find_by!(name: params[:id])
@posts = @category.posts
end
end
This of course implies that you have some sort of slugging in place that ensures that the name of the category can be used in the path of a URL. Gems like FriendlyID are your friend here.
Upvotes: 1