I have a controller with a method
def create
if passenger.valid?
....
end
In my Passenger model I have my validation rules. Those rules depend on from which method the validator has been called.
So the question is, how can I get inside my model the name method that called the validator, in this case 'create'?
Try this:
caller_locations(1,1)[0].label
I would suggest setting an attr_accessor in the model for this case
# In model
attr_accessor :validation_caller
def valodation_rules
if #validation_caller.eql?('create')
# validations
else
# validations
end
end
# in controller
model_instance.validation_caller = 'create'
Hope it helps..
Related
My controller has:
def create
#todo=Todo.new(params[:todo]).save
redirect_to todos_path
end
end
My model has:
class Todo < ActiveRecord::Base
end
This is due to strong parameters in rails 4 being the default.
A simple fix for this code is to have:
#todo= Todo.new(params[:todo].permit(:description)).save
in the controller
Also you can use the permit! method, which will add to whitelist an entire hash of parameters. It's described in documentation. But it's not recommended.
I have a field in my model for date created, this is not passed from the form and is currently set in the create method of my controller.
Should this be in my model instead in some sort of initializer method? If so what would that method look like?
I have other fields I want to set as a default each a record is created so I'm trying to find out where is the accepted standard place to put these. I'm starting to think it should be the model as if the model was ever called outside the controller it wouldn't have all this logic.
I generally create builders and never use directly the standard Rails method create.
The point is to gather all the logic in one place with particular cases etc...
Basically in controllers I end up calling the builders this way:
#my_model_instance = MyModelBuilder.new(current_user, params[:my_model]).build
#my_model_instance = MyModelBuilder.new(current_user, params[:my_model]).create
All my builders live in /app/builders
Here is a very basic example:
class MyModelBuilder
attr_accessor :params, :user, :my_model
# consider using a Struct if you keep a very basic initializer
def initialize(user, params)
self.user = user
self.params = params
end
def build
my_model
end
def create
my_model.tap{|m| m.save }
end
def my_model
#my_model ||= MyModel.new(default_values.merge(params))
end
def default_values
{
foo: 'bar'
}
end
end
Rails already manages the date of creation and update of your records.
If your model has a created_at field or an updated_at field they will be filled with the time of creation and update of your model.
You can generate those fields easily in a migration, for instance :
create_table :hello do
t.timestamps
end
Now, for default values, you can fill them in the initialize method of the model :
def initialize(*args)
self.field = default_value
super(*args)
end
In my controller i want to dynamically bind my instance method to the before_save callbacks.
Is there any ways we can dynamically bind methods to the callback from controller side....
EDIT :
Controller
This original code..
def amfupdate
set_properties
validate_record if params[:csv_header][:validate_record] == "Y" #On this condition...
super
end
If condition is true than i want to set custom callback that will exact call after before_save but before object is saved.
I want to call this method exact after before_save.. But if condition is true on controller side ..
In Model
def validate_record
self.csv_columns.each do |csv_column|
self.errors.add_to_base(_("Invalid column name #{csv_column.column_name}.")) \
unless self.model_name.constantize.column_names.include?(csv_column.column_name)
end
end
I think you're looking for something like the following. In the Model:
validate do |instance|
instance.csv_columns.each do |csv_column|
instance.errors.add :csv_columns, "Invalid column name #{csv_column.column_name}"
unless instance.class.column_names.include?(csv_column.column_name)
end
end
This will be called before the record is saved and will abort the save if the errors are added to
UPDATE: With suggestion for conditional validations
Add an attribute to the model
attr_accessor :some_condtional
Set this in the controller
#instance.some_conditional = true # or false
Then the validation now looks like this:
validate do |instance|
instance.csv_columns.each do |csv_column|
instance.errors.add :csv_columns, "Invalid column name #{csv_column.column_name}"
unless instance.class.column_names.include?(csv_column.column_name)
end if instance.some_conditional
end
Or something along those lines. In other words use the model to hold the state and communicate the logic
I have a record that needs to be validated before doing some action. Am I required to use a "valid?" method if I'm doing it with after_create?
For example, I have in my User model:
def after_create
if valid?
...
end
end
I thought it wasn't necessary to put in the valid method, but my application is telling me otherwise. Any idea?
You do not need the if valid? declaration there because after_create gets called after the record has already been validated (and created).
What do you mean your application is telling you otherwise?
Also, for the callback methods, you should use something like:
after_create :call_my_method
private
def call_my_method
# Do cool stuff
end
I am new to Ruby on Rails and have been using Scaffolding. On one of the forms I want to be able to have two fields and then have the difference between the two submitted to the database.
Instead of :pickupamount, I want (Ending Amount - Starting Amount) to be calculated and entered into the pickupamount column of my database.
Thanks in advance!
You could do this in either your model or your controller. Going along with Skinny Controller Fat Model, it might be better to put the functionality in your model. Check out ActiveRecord callbacks.
class MyModel < ActiveRecord::Base
attr_accessor :start_amount, :end_amount
before_create :calculate_pickup_amount
private
def calculate_pickup_amount
self.pickupamount = end_amount.to_i - start_amount.to_i
end
end
Then, in your controller:
def create
# Assuming params[:my_model] has all the data for initializing a MyModel,
# including start_amount and end_amount but not pickupamount:
my_model = MyModel.new(params[:my_model])
if my_model.save
# Yay, do something
else
# Fail, do something else
end
end
It might be useful to include the following extension method to Ruby's String class (thanks to sikelianos), perhaps in a file in your Rails app's lib directory:
class String
def numeric?
Float self rescue false
end
end
Then you could perform a check before setting pickupamount:
def calculate_pickup_amount
if end_amount.numeric? && start_amount.numeric?
self.pickupamount = end_amount.to_i - start_amount.to_i
else
# Throw exception, set some default value, etc.
end
end
In your view:
form_tag '/some_action' do
text_field_tag 'start_amount'
text_field_tag 'end_amount'
end
In your controller:
def create
model = Model.new
model.pickupamount = params[:end_amount].to_i - params[:start_amount].to_i
model.save!
end