Determine if an action acts on a member or collection

I am trying to find a clean way to determine which action (in the rails controller) is applied to members or to a collection.

For example, when you declare in routes.rb

resources :projects 

You get the following methods defined "in collections":

  • Index
  • create
  • new

and the following values ​​are defined on "on members":

  • update
  • show
  • remove

I am trying to find a way to use this excellent template in views, for example:

 <% if @controller.action.applies_on_members? %> <%= link_to :destroy, :method => "delete", :confirm => "RU Sure" %> <%= link_to :show, "show" %> <% end %> 

Similarly, this may be useful in before_filters.

 before_filter :find_project, :only_on_members => true 

Currently I have to do the following:

 before_filter :find_project, :except => [:new, :create, :index, :export_all, :destroy_all, :archive_all] 

This is quite annoying, and I think that all such actions have a common behavior: they are defined in collections.

Does anyone have an idea how to achieve this in a clean way?

NB: The reason I ask this question is because I am looking for something that is scalable from a development point of view, so that the behavior of before_filters or some partial elements is automatically inherited by new user actions.

Who never had to record something like

 <% unless ["new", "index", "some_other_action1", "some_other_action2", "some_other_action3", "some_other_action4"].include? @controller.action_name %> <%= link_to "Destroy", :project, :method => :delete %> <% end %> 
+4
source share
3 answers

Almost a year after the publication of this question, I know I found a reasonable solution to this question.

If we look at what on => :member and on => :collection really do, the difference is mainly that on => :member creates a path that includes the parameter :id , whereas the version on => :collection does not work .

A simple solution will then check if params[:id] empty or not in the user method. It will look like this (say, in application_controller.rb ):

 class ApplicationController < ActionController::Base def on_member? !params[:id].blank? end helper_method :on_member? #method will be accessible in views end 

As described in this post , for example, we can do something similar in the before_filter file:

 before_filter :find_project, :if => :on_member? 

In views, this allows me to check the type of the method as follows:

 <% if on_member? %> <%= link_to :destroy, :method => "delete", :confirm => "RU Sure" %> <%= link_to :show, "show" %> <% end %> 
+2
source

First of all, the template for working with collections and their records is part of REST , which is one of the pillars of Rails. What you defined is that REST calls collections and records . Theoretically, you can apply the most common HTTB verbs in a collection or in a record inside this collection, where: GET ; retrieve, put ; replace POST ; create and DELETE ; to destroy. Although it is a little incomprehensible what POST will do in one record.

In practice and in Rails, however, you usually use the ones you have identified:

  • Collections
    • Create Post ( POST )
    • View Records ( GET )
  • entrance
    • Update Record ( PUT )
    • Show Record ( GET )
    • Delete record ( DELETE )

These are RESTful routes added by Rails. However, as you know, Rails also includes two other actions for implementing a custom page that can provide the necessary data to these endpoints. ( new , change )

I rarely see people approach these definitions. Since I see this, there are at least two ways to solve this problem if you really want to solve it (see the bottom of the post):

You can defuse "_ normalize_callback_options" to get the exact syntax you suggested. This is relatively straightforward, but if the upstream does not change anything in the structure, you need to change the patch, so it is not very stable. Therefore, I would not recommend this approach, no matter how tasteful the syntactic sugar looks. Of course, you can also try to make this upstream, but it can hardly be accepted for the reasons mentioned below. :-)

Instead, I would put your definitions in an initializer: config/initializer/rest.rb

 ENTRY_ACTIONS = [:edit, :new, :show, :delete, :update] COLLECTION_ACTIONS = [:create, :index] 

Then use them in your filters, for example:

 before_filter :find_project, only: ENTRY_ACTIONS 

To access your views, add the entry_action? method entry_action? and collection_action? to your application helper:

 module ApplicationHelper def entry_action? ENTRY_ACTIONS.include?(controller.action_name.to_sym) end def collection_action? COLLECTION_ACTIONS.include?(controller.action_name.to_sym) end end 

Then in your views:

 <% if entry_action? %> # code <% end %> 

I would not extract this for constants myself, but just wrote the array directly, as it is much more clear, in my opinion, for reading when I return later. In addition, most people have had to think twice each time they come across these methods, which are far from optimal.

+1
source

You accept a very common problem that has already been solved in Rails for us and pretty much turns it upside down. Instead of asking the controller about its status throughout your application, you should tell your views and the controllers what they need to do, but they know how to do it.

Since you already know for sure that the actions of index , create and new apply to "collections" and that update , show and delete apply to "members", you must define each of the corresponding controller actions and views to work with such forms of resources.

Returning to the examples that you indicated, the links should be defined in partial and have an appropriate presentation template, made partial.

Your before_filter should be written as before_filter :find_project, :only => [:update, :show, :delete] .

Just the thought of seeing @controller.action.applies_on_members? calls @controller.action.applies_on_members? throughout your application, raises in my mind a flag that you need to rethink your design. Again, you are trying to solve a problem that Rails already cares about you.

0
source

Source: https://habr.com/ru/post/1482980/


All Articles