Trash implementation in rails app - ruby-on-rails

In my app I'm trying to implement trash for some objects, i.e. there will be column "trashed" and it'll set to date, when the object was trashed. Trash also has an index page, where users can restore objects - set "trashed" to nil.
I found examples of models with method trash!, that set trashed to date and it was implemented with Concerns. But I don't really understand how to implement controllers with action to_trash? Is there any way to use Concerns with controllers too or every controller should have it's own action and route for calling it?
Now I implemented it with controller Trash, that have action move_to_trash and every controller use this action, but I have to add get params trashable_id and trashable_type to do this. Is it a good way to do things?

I think the simplest implementation could be to add to your routes.rb file the following:
match ':controller/:id/trash', :action => :trash
This will allow you to use the action trash on every controller. Have a look at the Routing Rails Guide for more examples.
A simple implementation is the following (taking the model Report as example). I don't use Concern here:
class ReportsController < ApplicationController
def trash
#report = Report.find(params[:id])
<Do the trashing of report here, you know that already.>
# Decide what to do after having called #trash
respond_to do |format|
format.html { redirect_to(reports_url) }
end
end
end
If you have only some controllers that should allow the action, it is perhaps easier to add special routes rules for each controller, instead of adding it to every one. And if you want to go a step beyond, you may implement the trash action in a mixin, and mix it in the controller you want to have it in (and no, I don't will implement that, too).

Related

Ruby on Rails - Controller without Views

Iam new in Ruby on Rails. Normally I work with other web languages and now (of course) I try to compare it with other languages using on web.
But sometimes i have some problem to understand the philosophy and the character of Ruby on Rails. Of course i understand the concept of MVC.
But now Iam not absolutely sure:
Is ist OK to create and use a controller without views? In some cases you need a "class" for some usefull functionality used by other controllers they have views. Or is it a better style to use a module?
I try to find it out by reading a lot of articles and examples, but didnt find detailed information about this content.
When developing Ruby On Rails apps, it's recommended to put most of your business logic in the models, so for the controllers the logic need to be minimal to provide info for the views, so if it doesn't work with a view chance that you need a controller are really low.
Is it OK to create and use a controller without views
Yep it's okay.
The key thing to keep in mind is that Ruby/Rails is object orientated.
This means that every single you do with your controllers/models etc should have the "object" you're manipulating at its core.
With this in mind, it means you can have a controller without corresponding views, as sometimes, you just need to manipulate an object and return a simple response (for example with Ajax).
--
We often re-use views for different actions (does that count as not having a view):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def search
render :index, layout: false
end
end
The notion of skinny controller, fat model is sound in principle, you have to account for the times when you may need small pieces of functionality that can only be handled by a controller:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def update
#user = User.find params[:id]
#user.update
respond_to do |format|
format.js {render nothing: true}
format.html
end
end
end
A very rudimentary example of Rails is a drive-thru:
view = input interface
controller = accepts order & delivers
model = gets order packaged etc in backend
There are times when the controller may not need a view (for example, if you update your order with specific dietry requirements), and thus the notion that every controller action has to have a view is false.
It's really about making your controller versatile enough to manage your objects correctly.
Shared controller methods can be placed in ApplicationController. Also, in Rails 4 there are concerns (app/controllers/concerns/) where you can put the modules with methods that can be used by multiple controllers.
Controller handles request and renders corresponding view template. So controller without view is absolutely nonsense.
Every time request will execute this controller, it will just end with missing template error, so you will need to create view folder and put empty files with action name inside of it, which is obviously stupid.

Ruby on Rails RESTful controller function order

I'm pretty new to rails and have been going through the process of building a REST service. In the rails guide it seems pretty specific when they tell you where in the controller class to add their functions: create after new, show before new, etc. I guess I was just curious if there is some convention that most people use for ordering (when I rake routes the order is: index, create, new, edit, show, update, destroy). Not that its a big deal as long as your project is consistent, but is there a "conventional order" that people use? If not, I guess we could all argue about who's order is better.
Thanks!
The order of controller actions isn't really important at all, but I generally follow the same convention that Rails uses in it's own scaffolded controllers.
This way, I can easily scan to the controller action I'm looking for when I open a controller file.
Index, Show, New, Edit, Create, Update, Destroy
I think this order makes sense, as index and show are both concerned with "Showing" or "Reading" data, a primary concern in a web app.
Then new and edit, and create are concerned with "Creating", so they should be grouped together.
After create is update, which are usually very similar.
Then there's destroy, which is usually very simple and the only action of it's kind.
When adding custom actions to a controller, I keep them near the action they are most like, in terms of interactions.
If I have a method that is to display a subset or collection of things, I'll put it under index. If I have actions to upvote or downvote things, I think those fit nicely under update, since they are updating some part of the record.
Totally a personal decision but I do have a way that I set up my controllers:
def index end
def show end
def new end
def create end
def edit end
def update end
def destroy end
# non-restful endpoints/actions
For me, I like new/create and edit/update together since they, essentially, fire one after the other (when you are on the edit view, you're typically going to update the record, etc.).
Ultimately, I think having a system that works for you that you can follow and stay with is most important.

How do I determine the default action for a Rails controller?

I'm working on a functional test that needs to assert that a certain XHTML tag is present in a certain set of controllers. I'm basically doing this:
class ApplicationControllerTest < ActionController::TestCase
def setup
#controller = ApplicationController.new
end
# [...]
def test_foo_bar_and_baz_include_stylesheet
[FooController, BarController, BazController].each do |controller|
#controller = controller.new
get :show
assert_select 'head > link[rel="stylesheet"]'
end
end
end
The problem is that not all controllers have a :show action. What I need to do is ask either the controller or the routing configuration for the controller's default action and call get with that.
Update: Joseph Silvashy was right: I ended up separating my controller gets out into separate test cases. Solving the "default" route problem was bad enough, until I discovered that some of my routes had conditions attached, and I would have to parse them to craft the correct get call. And finally, Rails functional tests don't deal very well with calling get multiple times in the same test case, especially when that those calls are hitting multiple controllers. :(
I think the lesson here is one that we all know by heart but sometimes is hard to accept: if the code looks hairy, you're probably doing it wrong. ;)
Controllers don't have a "default" view or action, additionally actions can be named anything you want, they don't have to be the standard index, show, new, etc...
I'll probably have to :get the appropriate action for each controller you want to test. It's likely each test will be different down the road anyhow, even though right now they all have the same requirement, I think it makes sense to write one for each action regardless.
try to use the respond_to function: http://www.ruby-doc.org/core/classes/Object.html#M001005
to check if a method exitst.

RESTful membership

I am currentlly trying to design a RESTful MembershipsController. The controller action update is used only for promoting, banning, approving,... members. To invoke the update action the URL must contain a Parameter called type with the appropriate value.
I am not too sure if that is really RESTful design. Should I rather introduce sepearate actions for promoting,... members?
class MembershipsController < ApplicationController
def update
#membership= Membership.find params[:id]
if Membership.aasm_events.keys.include?(params[:type].to_sym) #[:ban, :promote,...]
#membership.send("#{params[:type]}!")
render :partial => 'update_membership'
end
end
end
Neither. The only "actions" a controller should handle are GET, PUT, POST, DELETE (+other http verbs). I realize posting this on a question tagged with "rails" is heresy but today I don't care.
One RESTful way to do this is to create new "processing resources" for each of these operations and POST the member to that resource to invoke the action.
When I say create a new resource, you can interpret that to mean, create a new controller.
To me this is one of the cases when you just shouldn't pull your hair out in efforts to adhere to REST conventions. Your model doesn't seem to fit in with the traditional CRUD concept, and the RESTful principle of differentiating actions via HTTP verbs doesn't seem to belong here too.
If I were you, I would split that action into separate actions for what you need to do with your memberships (trying to stay as DRY as possible). That would make the controller code more readable. And by creating some routes I would also make the view code cleaner (promote_membership_path, etc.). But that's just me :), so see what fits most for you.
EDIT:
here is an article which explains my point of view a bit: http://www.therailsway.com/2009/6/22/taking-things-too-far-rest
Well, there is more than one way to do things. The questions you should be asking yourself, is how many states are there? How often do new states get added? Etc.
If there wouldn't be that many states, I would create separate actions + a before filter for the find, but I think this is more of a personal preference. If you really want to keep it short, you can put each method on one line. So:
class MembershipsController < ApplicationController
before_filter :find_membership
def ban; #membership.ban!; render :partial => 'update_membership' end
def promote; #membership.promote!; render :partial => 'update_membership' end
protected
def find_membership
#membership = Membership.find(params[:id)
end
end
To answer your question whether it is RESTful: yes, your update method is perfectly RESTful, but remember that a PUT should be idempotent. So if I execute the same method twice, is the result the same? i.e. what happens if I ban a user and ban him again?

How do I redirect multiple actions to a single action while maintaining DRY?

I have an OptionsController, which contains an action account. The corresponding view has three forms, which post to three different actions, update_profile, update_user and change_password. Each action runs and then should redirect back to action, where the view is set up again and rendered.
I was trying to be DRY and create an after_filter to do the redirect:
after_filter( :only => [:change_password, :update_profile, :update_user] ) do |controller|
controller.send(:redirect_to, :action => :account)
end
However, this doesn't seem to get called; rather, the action complains that its view cannot be found.
Template is missing
Missing template options/update_user.erb in view path app/views
Is there any way I can do this in a DRY way, or should I just be sticking the redirect_to call in each of the three actions?
just put the redirect_to call in each of the actions. There is a fine line between DRY and unintelligible magic. I feel like trying to do something like an after_filter or anything else that nonobviously shatters the expected behavior of an action is probably too much magic.
It's my understanding that after filters are run after the response is sent to the client, meaning after any render or redirects occur, which is why you're seeing that error. They are intended to let you do things like log data, or benchmark or close connections or any other type of cleanup you have

Resources