Say I have a model called User that has the following parameters: favorite_color, favorite_animal, and lucky_number. The user fills in the form containing only favorite_color and favorite_animal. When the form is submitted, I want to run a function that takes the color and animal into account and comes up with a lucky_number. How do I insert a value to the post values without the user filling out the form - how and where do I implement this?
Thank you!
Since the lucky_number won't be known until after the favorite_animal and favorite_color are already recorded, it would be impossible to send it along with the post request. Try using a
before_validation_on_create
that looks something like this:
before_validation_on_create :generate_lucky_number
def generate_lucky_number
self.lucky_number = self.favorite_animal.length + self.favorite_color.length
end
This function just sets the lucky number to the combined length of the strings stored for the favorite color and favorite animal, and will set it before saving the user to the database.
You could build it into your controller logic, or place the code in your model in one of the following callbacks:
before_validation
before_validation_on_create
before_validation_on_update
Related
I'd like one of my models, Stones, to be generated at random using pre-defined options I've stored in a set of arrays and hashes. Instead of Create using params from the URL, I'd like new Stones to always be defined using this random generation process. I don't need any user input at all, except that each stone belongs to a given player.
I'm still new to rails; where should I put all this code? I know enough to be able to define the arrays and hashes and randomly select from them when I need to, but I'm not sure where and how to replace the part of the code that draws params from URLs and fills in a new record before it is saved. I know controllers are supposed to be skinny, so do I do this in the model?
Apologies if this is a duplicate. I searched extensively and couldn't find an applicable solution.
Thanks for any help!
I would create a service for this. Something like:
# app/services/stone_creator.rb
class RandomStoneCreator
RANDOM_FOOS = ['bar', 'baz', 'bat']
def self.call(user)
Stone.create!({
foo: RANDOM_FOOS.sample,
user: user
})
end
end
And then anywhere that you need a new random stone you can call it like:
random_stone = RandomStoneCreator.call(current_user)
I am currently in the process of making my first iphone app with a friend of mine. He is coding the front end while I am doing the back end in Rails. The thing is now that he is trying to send necessary attributes to me with a post request but without the use of a nested hash, which means that that all attributes will be directly put in params and not in a "subhash". So more specifically what I want to do is be able to retrieve all these attributes with perhaps some params method. I know that params by default contains other info which for me is not relevant such as params[:controller] etc.. I have named all attributes the same as the model attributes so I think it should be possible to pass them along easily, at least this was possible in php so I kind of hope that Rails has an easy way to do it as well.
So for example instead of using User.new(params[:user]) in the controller I have the user attributes not in the nested hash params[:user] but in params directly, so how can I get all of them at once? and put them inside User.new()?
I found the solution to my problem. I had missed to add the attr_accessible to my model which was what initially returned the error when I tried to run code like: User.new(params) having been passed multiple attributes with the post request.
The solution was very simple, maybe too simple, but since this is my first real application in Rails I feel that it might be helpful for other newbies with similar problems.
If you would like to just pass a more limited version of params to new, you should be able to do something like the following:
params = { item1: 'value1', item2: 'value2', item3: 'value3' }
params.delete(:item2)
params # will now be {:item1=>"value1", :item3=>"value3"}
Also see this for an explanation of using except that you mention in your comment. An example of except is something like:
params.except(:ssn, :controller, :action, :middle_name)
You can fetch the available attributes from a newly created object with attribute_names method. So in this special example:
u = User.create
u.attributes = params.reject { |key,value| !u.attribute_names.include?(key)
u.save
I have a model called Post in my Rails 3 app.
Users can create their own urls for these posts. (I call this a clean_url.)
If the user does not complete this field, I want to create the value myself from the title upon saving the form. (Essentially use the #post.title.to_s(some reg ex to remove spaces etc...)
What is the best approach to having the item save with title value in this field if it is left blank?
I assumed in the Posts controller create action I could "update_attributes" of the post upon saving... but Im beginning to think maybe this is wrong?
Anyone have ideas on how to achieve this?
Use a before_save callback, and a private method in your model. The following is taken straight from my blog source.
before_save :create_clean_url
private
def create_clean_url
if self.clean_url.blank?
# Remove non-alpha characters. Replace spaces with hyphens.
self.clean_url = self.title.downcase.gsub(/[^(a-z0-9)^\s]/, '').gsub(/\s/, '-')
end
end
I have the model:
User -1---n- Transaction(amount,description, date)
User -1---n- TransactionImport -1---n- TransactonImportField(name,value)
(personal expense tracking app).
What I want to achieve is this:
User opens URL and pastes the CSV with the list of transactions.
User submits it.
System extracts data from CSV into TransactionImport (row) + TransactionImportField (cell).
User can choose which column means what (amount, description, date) from the imported data in TransactionImport(Field).
User click save and the system transfers TransactionImport into the Transaction.
What I can't seem to get right is the fact that step 3 creates multiple records of TransactionImport (and related TransactionImportField).
So doing POST /transaction_imports?csv=abcd is expected to produce one record if we would be RESTful. But the code is supposed to be something like this:
# TransactionImportsController
def create
result = TransactionImports.parse(params[:csv])
flash[:notice] = result.message
redirect_to transaction_imports_path
end
I am probably approaching the task from a wrong angle as I feel that implementation doesn't fit in tp the inherited_resources.
Could you please advise what would be the most conventional way of implementing this?
Thanks,
Dmytrii.
REST/HTTP has no expectation that doing POST will only create one record. That maybe the default rails behaviour, but you should not constrain your design because of that.
I want the sign up form on my site to have a field that takes the sum of a math equation and use rails validation to validate it. Whats the best way to do it?
i.e
What is 6 + 9 ? [ 8 ]
Error Message : You have entered the wrong number
Override the validate method in your model class. Remember that the model object you create for the new action is a different instance than the one created for the create action, so you'll need to save the random seed or the math expression somewhere in your form so that you can recreate it during validation.
Then, something along the lines of:
def validate
unless math_equation_answered?
errors.add("math_answer", "is incorrect")
end
end
The implementation of math_equation_answered? is up to you, and math_answer should be changed to whatever model field you use for the user's answer.