Strong parameters in Ruby - ruby-on-rails

I'm getting the error message about strong parameters. I think it's just that rails 4 doesn't use attributes anymore. the code for my toy.rb is:
class Toy < ActiveRecord::Base
attr_accessible :name, :price, :vendor
validates :name, :presence => true
validates :price, :presence => true
validates :price, :numericality => true
validates :vendor, :presence => true
end
how can I change this to strong parameters?
EDIT: I used a different rb i changed it to employees and this is what I have:
class Employee < ActiveRecord::Base
params.require(:employee).permit(:first, :last, :salary, :salary, :ssn)
validates :first, :presence => true
validates :last, :presence => true
validates :salary, :presence => true
validates :salary, :numericality => true
validates :ssn, :presence => true
end
It's still telling me "ndefined local variable or method `params' for #"

The code you need is
params.require(:toy).permit(:name, :price, :vendor)
You will put this in your controller. Typically, you create a private method:
def create
Toy.create(toy_params)
end
private
def toy_params
params.require(:toy).permit(:name, :price, :vendor)
end
See http://guides.rubyonrails.org/getting_started.html#saving-data-in-the-controller for more information.
Edit
I think I might have misled you with my original answer. The code goes in the controller, not the model.

Strong params are designed to help your controller send specific data to your model. It's meant to protect your app against unauthorized data being passed:
#app/controllers/toys_controller.rb
Class ToysController < ActiveRecord::Base
def new
#toy = Toy.new #-> creates a blank AR object
end
def create
#toy = Toy.new(toys_params) #->creates new AR object (populating with strong params)
#toy.save
end
private
def toys_params
params.require(:toys).permit(:your, :params, :here)
end
end

Related

Rails Update method doesn't work

I want to update a prediction_config, but something is going wrong. Here are the relevant methods in my controller:
def edit
#prediction_config = PredictionConfigs.find(params[:id])
end
def update
#prediction_config = PredictionConfigs.find(params[:id])
if #prediction_config.update_attributes(params[:prediction_config])
redirect_to #prediction_config
else
render 'edit'
end
end
Here is my Model:
class PredictionConfigs < ActiveRecord::Base
attr_accessible :name, :value
validates :name, presence: true
validates :value, :inclusion => {:in => [0,100]},
presence: true
end
What could be the problem? Any help is appreciated!
EDIT: It is simply not updating the value, but everything loads properly.

Rails create a method accessible via both the model and controller

Is there anyway to create a function I can call both in the model and controller? I have a function that grabs an array of files and strips the extension off and want to validate against the list. However I also want access to this list in the controller so I can output a select box for the options. I currently have this, however the VALID_MODULES doesnt get populated all the time.
class Job < ActiveRecord::Base
after_initialize :init
VALID_MODULES =[];
validates :name, presence: true
validates :desc, presence: true
validates :api, presence: true, :inclusion => { :in => VALID_MODULES}
validates :filters, presence: true
validates :toe, presence: true
def init
Dir.foreach('lib/resources') do |item|
next if item == '.' or item == '..' or item == 'resource.rb'
#Wont be called very often so O(n) complexity is fine (small #elements)
VALID_MODULES.push(item[0..-4]) unless VALID_MODULES.include?(item[0..-4])
end
end
end
Instead of using a constant (VALID_MODULES), try making it an attribute of your job.
class Job < ActiveRecord::Base
attr_accessor :valid_modules
after_initialize :init
validates :name, presence: true
validates :desc, presence: true
validates :api, presence: true, :inclusion => { :in => VALID_MODULES}
validates :filters, presence: true
validates :toe, presence: true
def init
#valid_modules ||= []
Dir.foreach('lib/resources') do |item|
next if ['.', '..', 'resource.rb'].include?(item)
#Wont be called very often so O(n) complexity is fine (small #elements)
#valid_modules << item[0..-4] unless #valid_modules.include?(item[0..-4])
end
end
end
Now in your controller you can just call valid_modules on your Job object to return the array.
Example:
job = Job.new
job.valid_modules
# in config/initializers/api_modules.rb
module ApiModules
def self.modules
# the Dir[""] glob syntax here I believe exclude dot directories
# but I still like the Array#include? syntax here for your exclusions list
# you may need to massage the strings of your file list to be more appropriate to your case
#modules ||= Dir["lib/*"].select{|f| !["resource.rb"].include?(f) }
end
end
#app/models/job.rb
validates :api, presence: true, :inclusion => { :in => ApiModules.modules}

How to share validations accross models?

I have this validations in a model TipoMovimiento:
class TipoMovimiento < ActiveRecord::Base
before_validation :default_values
validates :codigo, :numericality => {:greater_than => 0}
validates :codigo, :descripcion, :sintetico, :presence => true
validates :codigo, :descripcion, :sintetico, :uniqueness => true
validates :descripcion, :length => {:minimum => 3}
validates :sintetico, :length => {:minimum => 2}
private
def default_values
self.estado ||= true if self.estado.nil?
self.codigo ||= TipoMovimiento.maximum(:codigo) + 1
end
end
Also, I have others models with the same fields, and I don't want to repeat these validations on them. How I do that?
I think you should use custom validations or inheritance.
What I would do is create a separate model:
module Validator
def self.included(base)
base.send :validates, :name, :presence => true
end
end
class User < ActiveRecord::Base
include Validator
end

Rails Nested Resource Routes

I'm fairly new to rails and I don't think I'm understanding the routing completely. When I try to access the edit action I get the following error:
ActiveRecord::RecordNotFound in StoreController#show
Couldn't find Gear with id=edit
Rails.root: /Users/dave/rails_projects/outdoor
Application Trace | Framework Trace | Full Trace
app/controllers/store_controller.rb:7:in `show'
Request
Parameters:
{"user_id"=>"104",
"id"=>"edit"}
Show session dump
Show env dump
Response
Headers:
None
Here is my view with the link that is throwing this error:
<li><%= link_to "Store Appearance", edit_user_store_path(#user) %></li>
Here is my nested route:
resources :users do
resources :store
end
Here is my controller
class StoreController < ApplicationController
def index
#store = current_user.gears.paginate(page: params[:page])
end
def show
#gears = Gear.find(params[:id]).user.gears.paginate(page: params[:page])
end
def edit
end
def update
end
end
Model Store
class Store < ActiveRecord::Base
attr_accessible :storeimage, :storename
belongs_to :user
validates :user_id, :presence => true
end
Model User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :userimage, :remove_userimage
has_secure_password
has_many :gears
has_many :comments, :dependent => :destroy
has_one :store, :dependent => :destroy
before_save :create_remember_token
require 'carrierwave/orm/activerecord'
mount_uploader :userimage, UserpicUploader
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :first_name, presence: true,
length: {:maximum => 50 }
validates :last_name, presence: true,
length: {:maximum => 50 }
validates :email, presence: true,
format: {:with => email_regex},
uniqueness: {:case_sensitive => false}
validates :password, presence: true,
confirmation: true,
length: {within: 6..40}
include Tire::Model::Search
include Tire::Model::Callbacks
def name
first_name + " " + last_name
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Please help.
You need to pass both the user_id and id params in the URL when you're accessing a store object nested under a user, so your URL should look like this:
/users/1/stores/3/edit
Versus:
/users/1/stores/edit
You also need to pass both of those as arguments to your path helper, ie:
edit_user_store_path(#user, #store)

Why aren't my before_validation methods firing if some validation is scoped?

In my model I've got a couple of methods to populate attributes of an Invoice before it is validated:
validates :account_id, :presence => true
validates :account_address, :presence => true
validates :number, :presence => true
validates :number, :uniqueness => true, :scope => :client_id
before_validation :generate_number, :associate_addresses, :on => :create
def generate_number
self.number = self.client.invoices.count + 1
end
def associate_addresses
self.account_address = self.account.addresses.first
end
And in the controller:
#invoice = #account.invoices.build(:client_id => #client.id)
if #invoice.save
#it saved
end
My problem is that the associate_addresses and generate_number methods only fire if I remove the :scope => :client_id argument on the :number validation.
Why would it skip the before_validation callbacks due to this?
Working in Rails 3.0.3
Thanks!
Thanks.
Don't know why it's skipping the before_validation methods, but to scope a uniqueness validation in Rails 3 you should use the following syntax:
validates :number, :presence => true, :uniqueness => { :scope => :client_id }
I guess that your syntax is making it try to add a scope validation, which doesn't exist. Probably there's a Rails bug that makes that skip the before_validation methods.

Resources