Reputation: 956
I have a class called Post, and I need to be able to accommodate the following scenarios:
I'm wondering if it's inevitable that my controller is just going to look gross with a ton of conditionals... here's my flawed approach at tackling this – does anyone know how I can accomplish this?
class PostsController < ApplicationController
def index
@user = current_user
# If a user has not specified a type or category,
# show them everything
@posts = Post.all
# If a user has selected a category, but no type, only
# show posts from that category.
if params[:category] && !params[:type]
category = Category.find(params[:category])
@posts = @category.posts
end
# If a user has selected a category and a type, only show
# posts from that category with that type
if params[:category] && params[:type]
category = Category.find(params[:category])
type = params[:type]
@posts = category.posts.where(post_type: type)
end
# If a user has selected a type but not a category, show all
# of the posts with that type
if params[:type] && !params[:category]
type = params[:type]
@posts = Post.where(post_type: post_type)
end
end
end
Upvotes: 5
Views: 4100
Reputation: 404
You can refactor your code a bit like this:
controller:
def index
@user = current_user
@posts = find_posts
end
private
def category
Category.find(params[:category])
end
def find_posts
if type = params[:type]
if params[:category]
category.posts.of_type(type)
else
Post.of_type(type)
end
elsif params[:category]
category.posts
else
Post.all
end
end
Add the scope to your Post
model, name it as you like:
scope :of_type, ->(type) { where(post_type: type) }
I recommend you using https://github.com/voxdolo/decent_exposure The code above is not the best, but you can improve it with this gem. You can even create a new class which will be responsible for finding posts and use this class in your controler.
Upvotes: 0
Reputation: 11509
You'll be better off following the convention of "fat models, skinny controllers", meaning you should put this kind of logic in the model itself. The Post
class should be able to report which posts correspond to your conditions, so you can define a method to do that:
class Post < ActiveRecord::Base
...
def self.by_category_and_type(category = nil, type = nil)
return where(category: category, type: type) if category && type
return where(category: category) if category
return where(type: type) if type
all
end
...
end
Then in your controller you can just call
@posts = Post.by_category_and_type(params[:category], params[:type])
I haven't tested this, but I think it should do the trick. Let me know if it doesn't!
Upvotes: 9