A good approach to different indexes of same resource in Rails? - ruby-on-rails

Something I've been wondering about is the best approach to creating a different index view of the same resource in Rails.
For example, let's say you have a group of Users, and the current Index action of the Users Controller that generates a tabular view of the users. You then want to create a second Index view that plotted all the users on a map. Would the best approach be to create a new action in the Users controller, or to create a new controller (like UsersMap) with a new index?
Thoughts appreciated...
My route file looks like this:
resources :users, :only => [:index, :index_with_map, :show, :edit, :update] do
match '/index_with_map' => 'users#index_with_map'
end
But hitting "users/index_with_map" results in:
ActiveRecord::RecordNotFound at /admin/users/index_with_map Couldn't find User with id=index_with_map

You could add that action to the UsersController, but if you are going to have more actions including Users and Maps, you might wanna think of making a new controller (to conform to the Single Responsibility Principle).
From the guides:
If you find yourself adding many extra actions to a resourceful route,
it’s time to stop and ask yourself whether you’re disguising the
presence of another resource.
You could do this:
resources :users do
collection do
get 'index_with_map'
end
end
This will enable Rails to recognize a path such as /users/index_with_map with GET.

The best approach would be to add new action that will deal with the users map. Then you will only need to create the corresponding view file for that action.
The users are for the same table, the functionality is only different. So why the need of different controller?
Also if you will create the another controller just for map view then there is no use of that as it's just a wastage of resources.
Another point is -
Controllers provides the user to interact with the model. So two controllers means you typically want two models. So different controllers are used when you want to do different (categories of) things.

Related

Rails 4 custom admin backend

I'm wanting to create an admin backend for a practice app. After reading around I've come to a general idea of what to do but would like some clarification:
Use namespace to route the backend at example.com/admin...
Put any adminifiable resources inside namespace e.g resources :posts
At this point do I duplicate the normal (public facing) controllers and put them into the admin directory? (Along with CRUD views)
In theory the public facing controllers only need index and show actions, right? As new/create/update/destroy will only be accessed in the admin/controller.
Any clarification or advice is greatly appreciated. Just trying to wrap my head around this.
I would recommend against duplicating your controllers, or any part of your application for that matter. That goes entirely against the DRY principle, which stands for "Don't Repeat Yourself." Duplicate code becomes really hard to maintain and test as your application grows.
Instead, I would recommend limiting access to certain actions using before filters. For example, let's say that you want users to be able to create posts, read posts and see listings of posts. In your PostsController, you can have something like this:
before_action :admin_user?, only: [:edit, :destroy]
Note: before_action is just the new name for before_filters.
So then actions like index would execute normally for all users, but if a user calls the destroy action, the controller would first check to see if the user is an admin, by calling an admin_user? method (typically defined in ApplicationController). This method could be a simple conditional, like "if the user is not an admin, flash an error message and redirect them back to where they were before the request" and then use it to protect any action or resource you want. You could also use it in the views to show delete buttons on posts only if the user is an admin, for instance.
That's for resource-specific actions. Often times it's also a good idea to have a section of the site that consolidates resource views and administrative actions. This would be its own controller/view (I call mine AdminController) and you can protect all actions in it with the above method:
before_action :admin_user?
To make your resources available to AdminController using the methods defined inside the individual resource controllers, you can do this in routes.rb:
namespace :admin do
resources :users
end
This will make it so that http://yoursite.com/admin/users/index will still call the index action in the Users controller, but it will happen within the context of an admin user (because of the before_action above).

Best practice for further actions in rails controllers

i'm just writing my first app in rails and i wonder, if there is a best practice to do the following:
i have a customer model created by a scaffold and pumping it up. a customer has to be displayed in a google map, so if go to /customers/23, the customer information are displayed. additionally i have a link within this page to show the user in a map (with a query ui dialog that comes up via ajax).
The question for me is, how does this fits in the normal crud structure of the model. Should i do like creating an action, called "show_map" and give it an extra route additionally to the resources routes? How do you handle this kind of things?
Lets do it like
resources :customers do
resource :map, :only => [:index]
end
it will generate routes like this
{:action=>"show", :controller=>"maps"} customer_map GET /customers/:customer_id/map(.:format)

Rails Controller - getting the index action to display only certain records

By default the rails controller will load all associated objects in the index action. What I would like to do is display only certain objects.
For example
I have a model called Car(id, make, model, year). I want list only particular makes in the index, depending on a parameter.
There are a few ways to do this, I'm just not sure which is best.
I could:
pass a parameter to the link:
cars_path(make: 'Acura')
and would give me /cars/?make=Acura
set up routes: (this seems to get messy)
match "cars/:make" => "cars#index", constraints: {make: /[A-z]{1,20}/}
or I could make a separate controller action for this
Any suggestion about what is the most "rails-y" way to do this? RoR 3.1
Usually, when we are talking of filtering data, I prefer to keep the same index action and filtering parameters via plain old GET vars (no extra route definitions) url?key=val&key-val.
This has a number of benefits among them:
url is bookmark-able
no session tinkering
I can reuse the filtering params and pass them to pagination links and such to have the filter follow the user while search is in order
I prefer not to make extra routes as the complexity of the filter can easily go too high. If the filter params are few and you are sure of what you are doing, you may define extra nice routes url/param/param but I find that those cases are few to none.
If you just want to display the cars of one make, the best url imo would be: /makes/1-Acura/cars. So you would just get the cars of this make in the cars controller.
Do you have a table for makes or is it just a string in your car table? I think you should have one.
resources :makes do
resources :cars
end
With these routes, you would have to test if there is a params[:make_id] in the index action of the cars controller, and if it's the case you would get the cars like that:
#cars = Make.find(params[:make_id]).cars
Or you could set up your routes like that
resources :makes do
scope :module => "make_scope" do
resources :cars
end
end
This way, you can have your controllers setup like that:
controllers
- cars_controller.rb
- make_scope (folder)
- cars_controller.rb
The path make_cars_path(#make) would hit the index action in the make_scope/cars_controller, so you would not have to worry about the presence of a params[:make_id], you would just know you're working with the cars of a make.
Otherwise, the get params are fine. I don't think it's bad to define a new route to get prettier urls though, depending on the complexity of your filters.

Ruby on rails - what should a controller look like when dealing with collections?

I have a simple application in which the user can manage decks of cards.
In my model I have:
Card
DeckOfCards
In my view /DeckOfCards/:id/edit
I want to allow the user to create a new card and add it to the current deck.
I currently have a form_for helper that posts to to /Cards/new
Should my Cards controller be hard coded to redirect back to DeckOfCards? What if later I want to create cards independently of a deck?
Another possible approach I am considering is a custom action on my DeckOfCards controller to handle this case. If I do that is there a way to use form helpers or does that require I post back to the associated controller for the object I am creating?
I am liking the structure that rails brings but when dealing with multiple entities it is not clear in my mind what the architecture should look like. I fear if I misuse these paradigms I will end up in a world of pain!
Can you recommend a more flexible way to approach this?
Thanks for any help
The setup should be quite simple:
You said you have two models: Cards and DeckOfCards. Perfect!
Now in your routes:
resources :cards
resources :deckofcards do
resources :cards, :controller => "cardsindeck" # gives you, e.g. <root>/deckofcards/1/cards/5/show
end
Now you need two distinct controllers for cards:
CardsController: handles CRUD for cards independent from DeckOfCards (you can still have links there to the DeckOfCards a card belongs to)
CardsInDeckController: handles cards through DeckOfCard's
In the CardsInDeckController, you can access the DeckOfCards the current card belongs to by params[:deckofcards_id], e.g. in your new action:
#card = DeckOfCards.find(params[:deckofcards_id]).cards.build

One Controller Action or Two for Ruby on Rails pages

I currently have one model, one controller with one action to list all the items in the model.
What I need to do is display different data from the model in two separate views. Is there a way I can use one controller action to display different views based on params, or should I create another action?
The reason why I hesitate to create another action is because I'll have to essentially duplicate all the routing I setup for the previous action.
Thanks for any ideas.
I'm not entirely sure that you've provided enough information to give what could be considered a 'good' answer, but if I'm understanding you correctly, this should be possible.
For example, couldn't you do something like this?
def show
#my_objects = MyObject.all
if params[:full_view]
render :action => 'show_full_fiew' and return
end
# if you get here, it will render the 'show' action
end
Let me know if that helps. If you could give some more information, I might be able to clean up this example to be a bit more informative.
You don't mention if you're using resource routes or not. If so, I'd just add a new option to your routes.
map.resources :products, :collection => { :some_great_name => :get }
You really shouldn't worry about adding views or new actions to your controller. An action should usually only have a few lines of code. If your controller actions start to grow in complexity you should think about moving that logic into your model.

Resources