Rails create a method accessible via both the model and controller - ruby-on-rails

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}

Related

how to query based on boolean attribute in rails?

I'm trying to query only objects from the database whose boolean attribute "in_season" returns true and its not working.
class Item < ApplicationRecord
validates :name, presence: true, uniqueness: true
validates :price, presence: true, numericality: true
validates :quantity, presence: true, numericality: { only_integer: true }
validates :description, presence: true
def self.in_season
where("in_season = ?", "true")
end
end
class ItemsController < ApplicationController
def index
#items = Item.in_season
end
end
I feel like everything is set up correctly and I'm not getting any errors, but my index page is blank because none of the items are being queried correctly.
You need to fix the syntax. Your mistake is that you're passing a string "true", whereas you want to pass boolean value true.
def self.in_season
where(in_season: true)
end
It's more Railsy to use scope for such needs:
scope :in_season, -> { where(in_season: true) }
Read more about scoping in Rails Guides on scopes.

How do I use an if statement in Rails validation?

I'm trying to create a validation statement that validates an object if service_area is present UNLESS service_area_radius==0
Here's the statement I created, which doesn't work:
validates :service_area, :presence => true, unless: "service_area_radius==0"
http://railscasts.com/episodes/41-conditional-validations
Like this:
validates_presence_of :password, :if => :should_validate_password?
validates_presence_of :country
validates_presence_of :state, :if => :in_us?
attr_accessor :updating_password
def in_us?
country == 'US'
end
def should_validate_password?
updating_password || new_record?
end
validates :service_area,
presence: {message: "Area Radius is missing."}, if: :radius_found?
private
def radius_found?
service_area_radius > 0
end
The validation for service_area will be executed if radius_found? returns true.
radius_found? will return true when the service_area_radius(attribute) hold value > 0.
Adding a custom message with message: option, when the validation fails.

Overriding presence true in User model

I have the following in my models/user.rb:
validates :company, presence: true
validates :title, presence: true
I have a secondary view where I want to create a user but not require this user to enter a company and a title. How would I do that without modifying the main user.rb?
This is for Rails 3.2
You can do by declaring custom validations the way #BroiSatse has answered or when saving the user you can pass validate: false as argument, do this way
#user.save(:validate => false)
I usually do sth like:
class User < AR::Base
validates :company, :title, presence: true, if: :validate_company_and_title?
def validate_company_and_title?
#validate_company_and_title.nil? || #validate_company_and_title
end
def skip_company_and_title_validation!
#validate_company_and_title = false
end
end
Then in your controller create action for given view you can do:
#user.skip_company_and_title_validation!

Default value along with uniqueness validation

I have a Path model with name attribute as unique. I want to set default value as '/'
to the same.
I have done in the following manner.
class Path < ActiveRecord::Base
attr_accessible :name
validates :name, presence: true, uniqueness: true
before_validation :set_default_path
private
def set_default_path
self.name = name.presence || '/'
end
end
Domain model is designed as:
class Domain < ActiveRecord::Base
attr_accessible :name, path_id
validates :name, :path_id, presence: true
validates :name, uniqueness: {scope: :path_id}
end
But this doesn't work for consecutive inserts with a blank name for path.
path = Path.find_or_create_by_name('')
domain = Domain.new(name: 'stackoverflow.com')
domain.path = path
domain.save! # Fails with validation error
ActiveRecord::RecordInvalid:
Validation failed: Path can't be blank
Is there a robust way to achieve this ?
You should remove following callback
before_validation :set_default_path
and use validation for name as following:--
validates :name, presence: true, uniqueness: true, :if => 'name.present?'
and write a migration file to add default value to name attribute of paths table as either of followings:--
change_column :paths, :name, :string, :default => '/'
or
change_column_default :paths, :name, '/'
add condition on validation:
validates :name, presence: true
validates :name, uniqueness: true, unless: proc { |e| e.name == "/" }

Strong parameters in Ruby

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

Resources