How can I maintain DRY code on polymorphic controllers and views? For
example, I am building an app where users have many posts and at the
same time a group can have many posts and a category can be related to
many posts (post belongs to a user, category and a group).
groups/1/posts
users/1/posts
category/1/posts
So what happens then to the posts_controller? How can I know for
example if I want to show the posts for a group, the posts of a
specific user or category?
Someone could tell me to do something like this:
def index
if params[:group_id]
@posts = Post.find(:all, :conditions => ["group_id = ?,
params[:group_id])
elsif params[:user_id]
@posts = Post.find(:all, :conditions => ["user_id = ?,
params[:user_id])
elsif params[:category_id]
@posts = Post.find(:all, :conditions => ["category_id = ?,
params[:category_id])
end
end
But then again this code will be unsustainable in the future when more
routes are added (ifs block will be hell). And when I take into
account that the views and links should render differently for each
case makes it worst.
What's the best solution for this? Any suggestions or guidelines are
appreciated.
Well, I think I didn´t write my question correctly, I'll try to be
more explicit.
In the app I am working on, users can create posts like in a blog. The
app emphasizes on the fact of belonging to a group. So a post belongs
to a group and a user (table posts has a user_id and group_id column).
I want to show the list of posts that belong to certain group. I use
the index action from the posts_controller to show all the posts that
belong to a certain group through the route groups/1/posts. Also, I
show other things such as: most recommended posts and more active
users, all in the same index action and view.
It's here where the problem starts. I want to also show the index of
the posts made by a specific user (the route should be users/1/posts)
and additional info too. I thought about using chains of ifs and elses
(asking for params in the route to know which data to show) in the
index action and views as an "easy, dirty and unmaintainable
solution". But there are more problems. There should be a option to
filter the posts of a group by category and tags (and this too applies
to posts for a specific user). This is where the problems becomes a
snow ball. The fact that there should always be filtering for a
specific group or user. And that's without taking into account the
views which will show different information depending on the context
(user or group). I thought about having various controllers but it
seems illogical: post_users, post_groups, post_user_categories,
post_group_categories, post_user_tags, post_group_tags...
So that's it. I don't know which is the right move. Any help or
suggestion is appreciated.
Well, I think I didn´t write my question correctly, I'll try to be
more explicit.
In the app I am working on, users can create posts like in a blog. The
app emphasizes on the fact of belonging to a group. So a post belongs
to a group and a user (table posts has a user_id and group_id column).
I want to show the list of posts that belong to certain group. I use
the index action from the posts_controller to show all the posts that
belong to a certain group through the route groups/1/posts. Also, I
show other things such as: most recommended posts and more active
users, all in the same index action and view.
It's here where the problem starts. I want to also show the index of
the posts made by a specific user (the route should be users/1/posts)
and additional info too. I thought about using chains of ifs and elses
(asking for params in the route to know which data to show) in the
index action and views as an "easy, dirty and unmaintainable
solution". But there are more problems. There should be a option to
filter the posts of a group by category and tags (and this too applies
to posts for a specific user). This is where the problems becomes a
snow ball. The fact that there should always be filtering for a
specific group or user. And that's without taking into account the
views which will show different information depending on the context
(user or group). I thought about having various controllers but it
seems illogical: post_users, post_groups, post_user_categories,
post_group_categories, post_user_tags, post_group_tags...
So that's it. I don't know which is the right move. Any help or
suggestion is appreciated.
Reposting, since I think this may be close to what you're looking for:
def index
args = {}
[:user_id, :group_id, :category_id, :tag_id].each do |k|
args[k] = params[k] if params[k]
end
@posts = Post.find(:all, :conditions => args)
end
Which will filter for the following, assuming you've setup your routes
correctly:
/users/1/posts
/groups/1/posts
/categories/1/posts
/tags/1/posts
/users/1/categories/1/posts
/users/1/tags/1/posts
/groups/1/categories/1/posts
/groups/1/tags/1/posts
...
/groups/1/users/1/categories/1/tags/1/posts (although I doubt you'll
be having this kind of route)
In short, it will accept filters for a route with a combination of
users, groups, categories, and tags.
I guess I'll have to put some extra ifs and elses because I have to
show additional data on the index action and view. (not only @posts,
for example for group index posts I must show a list of latest posts
from the group, but also the most commented and active posts + a tag
cloud.
Your proposed solution is good, but I am worried about the views. Any
ideas on how to maintain the views clean and dry? I am imaging myself
writing tons of ifs and elses on the index view.