My class has a column secret which I generate using a specific process. Because of this, I don't want to let the user update this field via an edit form.
However, if the user adds manually the secret tag to the form and submit it, my object's secret gets updated too.
def update
object.attributes = params[:my_class]
end
I guess I create a before filter like this one
before_filter :clear_secret, :only => :update
def clear_secret
params.delete(:secret)
end
I would like to know if there is a better way to do this. Could I do this from the model? Is there a already existing Rails method for this?
If you're using Rails 3, you can protect this via attr_protected
class YourModel < ActiveRecord::Base
attr_protected :secret
end
A user attempting to inject a secret field into the form will instead cause Rails to raise a ActiveModel::MassAssignmentSecurity::Error.
However, this mechanism is deprecated in Rails 4 in favor of the strong_parameters mechanism referenced by #gylaz.
It's conventional to use strong_parameters gem to do this.
Using said gem you can permit only the attributes that can be updated, like this:
params.permit(:some_attr, :another_attr)
Related
for now when i click user with id = 1, on url bar its
users/1
I want to change it to
users/[encrypt]
or
users/some_user
is there any way to do that on rails?
What about using a permalink instead of the users id? i.e. users/[permalink] and you can configure the permalink to anything you like as long as it is a unique value
Checkout the friendly_id gem: https://github.com/norman/friendly_id
Rails uses to_param method when displaying object in url.
If you change to_param method in user it will, be used to display data instead of id.
By default rails has implemented to_param to return id of the object.
For example
class User < ActiveRecord::Base
...
def to_param
"#{self.first_name}-#{self.last_name}" # or whatever you want to use
end
...
end
In your url you will have /users/first_name-last_name or whatever your to_param method returns. By default to_param returns id and in url you get /users/4. and in your controller you can find user with id 4, but when you change to_param method, you have to change respectively the way you fetch user from database.
Example:
I change my to_param method to return nick_name from database, and it is unique for the particular user, that I can use to find user from database.
In router
change the mappings for params
get 'users/:nick_name', 'users#show'
In controller
User.find_by :nick_name => params[:nick_name]
like others in this post says , i use
i use
https://github.com/norman/friendly_id this way:
# app/models/secret.rb; this would go in the model you want to obfuscate
class Secret < ActiveRecord::Base
has_friendly_id :code, :use_slug => true
validates :name, :uniqueness => true
def code
Digest::SHA1.hexdigest self.name
end
end
it’s simple. If your security needs are serious you’d probably want something a little more complex (not to mention more layered than a basic obfuscation technique), but I wanted to share an out-of-the-box way to use a gem that already exists (and may even be in use in your app already)
I am trying to follow a ruby on rails scaffold example.
I am using ruby version: 2.1.5 with rails version : 4.1.8
I have used this command:
rails generate scaffold User name:string email:string
This worked fine - I can run the example which shows crud functionality to my generated scaffold. The examples I have been following advise to look at the model file generated. The ones in the examples seemed to have a value called attr_accessible - but for me this was not generated - I do not know why - it seems to be quite useful so you can easily see what is inside your model? My model looks like this:
class User < ActiveRecord::Base
end
I altered it to look like this :
class User < ActiveRecord::Base
attr_accessible :name, :email
validates :name, :presence=>true
end
and when I now visit localhost/users I get the error:
Can somebody please tell me how a generated model can be created with this attr_accessible line, and how I can add an example of validation to the model.
Rails 4 doesn't use attr_accessible; it uses Strong Parameters.
They both serve as a guard for mass assignment of params, often times used during form submissions.
The scaffold doesn't support automatically setting strong params as far as I'm aware, in part because people implement strong params white listing very differently.
A couple more links on Strong Params
How is attr_accessible used in Rails 4?
https://github.com/rails/strong_parameters
https://github.com/elabs/pundit#strong-parameters <= I strongly recommend this gem
To me this suggests whatever guide you're following is out of date.
I think the problem is that the scaffolding that you have used is not compatible with how Rails works in later versions. In earlier versions of Rails, attr_accessible was used for preventing security problems related to mass assignment. In later versions, the countermeasure changed and moved to the controller instead of the model.
If you still want to use the attr_accessible macro, you can add gem 'protected_attributes' to your Gemfile and install with bundler.
You shouldn't add them in the model.
The stuff you wanna access goes into the controller, like
def index
#users = User.all
end
def show
#user = User.find(params[id])
end
...
private
def user_params
# It's mandatory to specify the nested attributes that should be whitelisted.
# If you use `permit` with just the key that points to the nested attributes hash,
# it will return an empty hash.
params.require(:user).permit(:name, :mail)
end
so you can use them afterwards in your views.
e.g. in app/views/users/show...
<h1>#user.name</h1>
<p>#user.email</p>
I have Customer and each customer has_many Properties. Customers belong to a Company.
I'm trying to add a certain Property to each one of a single Company's Customers. I only want this change to happen once.
I'm thinking about using a migration but it doesn't seem right to create a migration for a change that I only ever want to happen once, and only on one of my users.
Is there a right way to do this?
You can just use rails console.
In rails c:
Company.where(conditions).last.customers.each do |customer|
customer.properties << Property.where(condition)
customer.save!
end
Validation
Depending on how you're changing the Customer model, I'd include a simple vaidation on the before_update callback to see if the attribute is populated or not:
#app/models/Customer.rb
class Customer < ActiveRecord::Base
before_update :is_valid?
private
def is_valid?
return if self.attribute.present?
end
end
This will basically check if the model has the attribute populated. If it does, it means you'll then be able to update it, else it will break
--
Strong_Params
An alternative will be to set the strong_params so that the attribute you want to remain constant will not be changed when you update / create the element:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
...
private
def strong_params
params.require(:model).permit(:only, :attributes, :to, :update)
end
end
It would be much more helpful if you explained the context as to why you need this type of functionality - that will give people the ability to create a real solution, instead of proposing ideas
In Rails 3, we can define the accessible attributes:
attr_accessible :rating, :review
In this model, there is additional user_id which is protected to prevent forgery/hacking. This value is assigned in the controller:
#review.user_id = current_user.id
If I use Firebug to manually include the user_id, it will be part of the params[:review], but of course since user_id is not defined in the attr_accessible, it wouldn't get saved into the database. Such case is rather secure.
Question 1
I read in Rails 3 In Action book, Yehuda Katz included .delete method to delete unauthorized params before further action is performed: params[:review].delete(:user_id). Should I include this as well to further secure my app, or just ignore this step?
Question 2
If I should include the method above, I would like to have something like .delete_all_except to just strip it to the allowed attributes in the params. How do I do that?
Thanks.
If enabled, Rails 3.2 will through an exception if additional mass-assignment params are sent to the model
config/application.rb
config.active_record.whitelist_attributes = true
Rather than deleting out parameters you don't want, I recommend only accepting parameters you do want:
#user.update_attributes params[:user].slice(:rating, :review)
This will only return the user params you allow.
note: in Rails 4 (coming soonish), this behavior is implemented with a DSL named strong-parameters. You can install this gem in Rails 3.2 to implement now:
#user.update_attributes params.require(:user).permit(:rating, :review)
I have a couple of fields created_by and updated_by in most of my tables. This would contain the user id of the user who created or updated the Object. is it possible to have a similar function like how rails handles created_at? I basically want it to function the same way as the timestamps insertion. I should be able to define in the columns in the migration script and configure rails to fetch the user object from a helper method everytime when it changes the particular object. Is there a direct way to do it or is there a plugin which does this?
Also you can do this without gems but with Rails Observers
You can create observer like this:
class UserTouchObserver < ActiveRecord::Observer
observe :product, :post, :comment
def after_create(model)
update_attribute(:created_by, current_user.id) if model.respond_to?(:created_by)
end
def after_update(model)
update_attribute(:updated_by, current_user.id) if model.respond_to?(:updated_by)
end
end
I was able to find a few plugins on github that do just this:
https://github.com/jnunemaker/user_stamp
https://github.com/bokmann/userstamp_basic