I have user role based access control. User has many roles.
Each role has access to some controllers, actions and scopes.
I have method can_control?(controller) in User model which check if user have access to specific controller. I have similar method to actions.
Then in view or controller I can make simple logic to hide some information or permit access using:
current_user.can_control?(controller_name)
I wonder if it possible to create method in User model which automatically takes controller_name. I tried to define method in model.
def can_control?
self.permitted_cotrollers.include?(controller_name)
end
But it gives me an error:
undefined local variable or method `controller_name' for #<User:0x007f00e8ceb928>
I understand error, but can find solution or if it possible to have one.
Here is the best solution I can think of : You can access the current controller name in params[:controller] from any controller method.
In User model :
def can_control?(params)
self.permitted_controllers.include?(params[:controller])
end
In any controller :
current_user.can_control?(params)
In your model, you can get the standard associated controller name by using :
"#{self.class.to_s}Controller"
self refers to your model
.class gets its class
.to_s converts its class to a string containing its class name
If you need it written in snake_case instead of CamelCase, use this :
"#{self.class.to_s.tableize}_controller"
.tableize converts the CamelCase name of your model into the snake_case name used in your controller
Related
I created a Foo controller, and the Foo view allows users to enter and submit a URL. In my Foo helper I have a block of code which scrapes the URL entered by the user (Using nokogiri). How do I pass the url received from the user to the helper so that URL can be parsed and saved to the db? Should I set this up differently?
One way to archive this in Rails 3 is to call view_context inside the
controller to create a new ActionView instance for a controller, then
all helper methods will be available through this instance in the
controller.
view_context.scrape_url_method_in_helper
Or do this in FooController
include FooHelper
Also, read rik.vanmechelen's comment below.
If there is a request parameter 'name' passed to an action, we can receive it in our Action class if we have a field named 'name'. Which interceptor is responsible for doing this ? I looked at the code for ParametersInterceptor, but it only sets the parameters onto the value stack, not in corresponding fields of the action class
but it only sets the parameters onto the value stack, not in
corresponding fields of the action class
There is just a little glitch in your reasoning: The action class is is at the top of the value stack! So com.opensymphony.xwork2.interceptor.ParametersInterceptor is responsible.
As a piece of advice, though, I would suggest that you don't actually have a parameter named "name" on the action class, but rather move such fields from your action class into another class that will serve as your "model". Then, have your action class implement the ModelDriven interface. This will place the model class on the top of the ValueStack instead of the action class instance, and then the "name" parameter will map onto your model instance.
The separation of the model/data concerns into another class from the action/control concerns will make your code more readable and maintainable. Of course, if there is only, say, a single param, then separating it into a separate class would be silly. More than 2 or 3 params, though, and you will benefit from the separation.
I have created a instance variable in rails project, which gets its value from a url parameter like example.com/value. This variable is created in new action, now can it also be used in create action, of the same model.
The value is a id of another model altogether and both the models are associated, I need to create the instance variable in former model.
I need to know, for how long the instance variable is available, and can be use the instance variable of one model in another model.
Clarification with real example
Supposingly there are two models, one is User model and other is Referral model. The root is root :to => 'users#new. Now the user will coming here via example.com/value, where value is the id for Referral model. Now using this value I have to increment two fields: One is visits, which shows how many visits did that particular url bring. Other is signup, which will increment if there is a signup using that value.
I have passed this value via routes in users#new, which I use to increment the visits column of Referral model. Now if the users signup, the users#create would be executed, and I want to be able to use the value in the create action as well, to increment the signup column in Referral model.
As of now, I understand that the instance variable I created in new action to store the value cannot be used in create action. Now how can I achieve this.
In general instance variables only last as long as the user's HTTP request, so they can not be created in one action and used in another.
You could try storing the variable in the session, a hidden input field on the HTML form generated by the new action, or in the urls of links generated by the new action.
I don't know exactly what you are doing, but from the names of your two actions it sounds like there is probably an HTML form involved, so I think the best thing is to use a hidden input, something like this:
<input type="hidden" name="model_id" value="<%= #model_id %>" />
Instance variables only last for that call and in the class they are defined, with the exception of the views. If you have a controller with two methods where one method is your route and another is used internally, then it will be available to both, it is also available to your views.
e.g.
test_controller.rb
def index
something_else
p #variable #outputs "foo" in the terminal
end
def something_else
#variable = "foo"
end
However it would not be available between create and new as these would be called in different requests.
I am using Ruby on Rails 3.0.7 and I would like to retrieve a controller name given a class name. That is, I have
Articles::Category
and I would like to retrieve
articles/categories
I would like to retrieve the controller name inside a view file not related to the Articles::Categories controller.
How can I do that (possibly using some Ruby on Rails core method)?
Articles::Category.name.underscore.pluralize
=> "articles/categories"
As mentioned by many others, there is no special method for that. But as long as you followed Rails conventions, this approach will take you far.
To get the controller name, say inside your view, you can do :
<%= controller.controller_name %>
To get the name of a class, say User, if you have a user object named user :
user.class.to_s
Other than that, i don't think there's a correlation between a controller and a model, that can give you the controller name from a class name, because they are different things. You can maybe create a hash like {:controller => 'class_name'} and map those yourself.
Articles::Categories.name.underscore #=> articles/categories
And it underscores camelcased words to so that:
RailsAdmin::ApplicationHelper.name.underscore #=> rails_admin/application_helper
Assuming that you really meant Articles::CategoriesController then Articles::CategoriesController.controller_path will give you what you want.
Update The question is, given the name of a Rails Model, how do you get the name of the associated controller?
The answer to that question is, you can't. There is not a one-to-one mapping from the model name to the controller name. The User model could be controlled by the users_controller.rb and/or admin/users_controller.rb or not have an associated controller at all. You can certainly guess at some likely possibilities based on Rails conventions but you can't know.
Instead of underscore.pluralize just use tableize:
ActiveRecord::Base.name.tableize
=> "active_record/bases"
In certain Controller I have CRUD methods. In order to access these methods user needs to be logged in. This is why I used [Authorize] attribute for this controller. Now I need additional attribute which would check if item that user wants to view/delete/update belongs to him.
Is it possible and recommended to do this with attribute or you would suggest using check methods inside each method? If you suggest using attribute, could you please provide me some links/instructions?
EDIT:
Ofcourse, if attribute returns false than I don't want to redirect user to login page but show him an error message...
It can be done with a custom Authorize attribute, but it's much cleaner to put the logic inside your controller methods.
The attribute is related to the action being called (the controller class method). On that basis any attribute relating to the user's ownership of the object being manipulated (from your Model) should really be on the entity/class that the user is attempting to manipulate. You'll probably find it easier to validate the user within the Model method rather than using an attribute to achieve this.
In my opinion it is possible, just google for 'Custom Authorize Attribute'.
But maybe it is better to query your database with something like this:
ContextOrSession.Query<Something>.Where(Something.Groups.Intersect(User.Groups).Count>0)