Rails need advice on controller practices - ruby-on-rails

I try to follow RESTfull approach in controllers, but sometimes I need action which won't fit into default ones. E.g. I have an index action rendering all articles which is
def index
#articles = Article.all
end
but what if I also want search them? should I create separate actions for it, or should I bloat existing controller, like:
def index
if params[:search]
#articles = Article.where(id: params[:search_id])
else
#articles = Article.all
end
end
What is the right way?

You should use same action and create a index action only. And search logic goes to Article model.
You should follow this

I would keep it in index. If you want to keep it clean and standardise it you could change the controller code thus:
def index
#articles = Article.search(params[:search])
end
and then add a class method in Article
class << self
def search(options={})
if options.blank?
return self.all
else
..other search logic
end
end
end
Note that the example you gave for a search doesn't really make sense as it's specifying the id of the article. If you already know the id then that's not really a search: you might as well just go to the show page for the article.

Related

Letting admin see all posts by all users in rails

Rails and programming noob here. I am a teacher trying to create a god mode where I can view/edit etc posts of my students, however, students should be only able to view their own posts with this in the posts controller:
def index
#posts = Post.where(user_id:current_user)
end
But how do I create an index for me to see everything?
Create an AdminController with the following index method.
def index
if params[:user_id]
#posts = Post.where(user_id: params[:user_id])
else
#posts = Post.all
end
end
This method will show posts of a certain user if the url parameter user_id is set and shows all posts on the system if the url parameter is not specified.
I would recommend using pagination like kaminari for example.

Having multiple instance variables in rails controller action? (Rails best practices)

Say for example I have two models, posts and category. Now say I want to make it so the from the category show page you can create a new post using the form_for method. To do this, you will obviously need access to the #category variable and a new instance of a post (#post). Is this acceptable code in the controller?
#app/controllers/categories_controller.rb
def show
#category = Category.find(params[:id])
#post = Post.new
end
Or is it bad practice to have two instance variables defined in the one controller action - and if it is, what would be the best practice for a case like this?
I usually do something like:
#app/controllers/categories_controller.rb
helper_method :category
helper_method :post
def show
end
private
def category
#_category ||= params[:id] ? Category.find(params[:id]) : Category.new(params[:category])
end
def post
#_post ||= Post.new(params[:post])
end
Then, in your views, just refer to post or category (not #post or #_post). The nice thing is you can remove the same logic from your new, delete, etc methods...
Actions related to posts should be in the PostsController as much as possible.
Let's say the user is looking at all posts under the category "rails": /categories/rails
There's a button on that page to create a new post under the "rails" category, href: /posts/new?category=rails
This takes you to PostsController#new where you instantiate a new Post, validate the category param and build a view. This view could either be a new page, or a modal popping up.

Adding a wildcard to Rails route

In my Rails 4 project, I have a route like this (via rake routes) :
user_articles_path GET /users/:user_id/articles(.:format) articles#index
This works beautifully so that /users/1/articles shows user 1's articles.
What's the simplest way to get all articles from all users?
Something like /users/*/articles or /users/all/articles would be sweet.
Here's the Articlescontroller index method:
def index
#articles = if params[:user_id]
user = User.find(params[:user_id])
user.articles.where('content like ?', "%#{params[:search]}%").page(params[:page]).per_page(5)
else
current_user.articles.where('content like ?', "%#{params[:search]}%").page(params[:page]).per_page(5)
end
end
I show articles based on a user/id and then if a user is logged in (via Twitter) I show them their articles.
Update
Not sure if this is too hacky, but here's my current index method. It works like I want, but it could probably be simplified:
def index
if current_user
if params[:user_id]
user = User.find(params[:user_id])
#articles = user.articles.where('content like ?', "%#{params[:search]}%").page(params[:page]).per_page(5)
else
#articles = current_user.articles.where('content like ?', "%#{params[:search]}%").page(params[:page]).per_page(5)
end
else
#articles = Article.all.where('content like ?', "%#{params[:search]}%").page(params[:page]).per_page(5)
end
end
Articles are there for logged in and logged out users with easy routing to show a specific user's articles. Suggestions for cleaning it are welcome.
The best way is to use the Article as a resource in your route file:
resources :articles
Doing this you will have to create an ArticleController and with the path /articles you'll be redirected to a new set of views that will load all the articles without handling the user they come from. Eg. in the index action of this controller:
def index
#articles = Article.all
end
This is the best way to handle a REST interface in Ruby, since you are querying the Article resource alone here, and you should not pass through the User resources.

activeadmin override index action

my problem is related to customization in ActiveAdmin.
First of all I can't get how to override index action. Everything looks simple according to the documentation but very few things work as expected. Eventually I came up with these two alternatives. First one is a blogpost which presents the following solution (which appear to work).
scope_to do
Class.new do
def self.projects
Project.where(:id => 1)
end
end
end
While this one, which is the solution for issue#511 does not work. Can anyone tell why??
scope_to :current_project
controller do
private
def current_project
Project.where(:id => 1)
end
end
What's your experience? How do you achieve index action customization?
I'm an experienced web developer but I'm new to Ruby world in general.
Do you think it's a good idea to use ActiveAdmin for a production project? What's you pick when it comes to Admin interface?
I've read about Rails Admin but looks like it's not easy to customize.
My biggest concern at the moment is about active admin not easy to customize to achieve UI or behavior which are very different from the ones that it offers by default.
What do you think?
If you want to customize controller see https://github.com/josevalim/inherited_resources. For example:
controller do
def index
# something
index! do |format|
format.html { redirect_to some_url }
end
end
protected
def collection
#projects ||= end_of_association_chain.paginate(:page => params[:page])
end
end

rails controller design : listing and create on the same view

starting from the rails blog tutorial, i want to have listing and create functionality on a single view. But i don't known how to design the controller to accomplish this.
The index view must show a simple list of posts and a form to create a new post.
Can i solve this with partials? How? I need a "new" and "create" methods? With only create is not enough?
class MyPostsController < ApplicationController
def index
#posts = Post.all
end
def new
end
def create
end
end
If you want to have the form in the index view, render the form. I'd recommend a partial, but it's not mandatory. Depending on the form implementation you may need a new Post model, that's as easy as putting a #post = Post.new in the index action.
The reason create may not be "enough" is because some forms are "for" an instance of the model. In those cases generally the new action makes a new Post and renders the form, whereas the create action actually saves (creates) it.

Resources