Processing data before saving to database - ruby-on-rails

I have decimal field in my DB. Users can input values in two formats: with comma or point (11,11 or 11.11).
But MySQL allows to save data only in 'point' format, so i want to process data before saving with regex like this:
sub(/,/,".")
How can i do it in Rails3?

If I understand you correctly, this could be done in the controller or the model. I might use the before_save callback in the model to achieve this in the following way:
class Item < ActiveRecord::Base
before_save :standardise_numbers
...
protected
# Called before this object is saved to the DB
def standardise_numbers
self.number.sub!(",", ".")
end
end
Where number is the attribute you're wanting to convert.
I assume you don't need to convert it back to comma representation to display to the user? If you do, you may want to look into the internationalisation API for Rails, Il8n. It handles this kind of stuff and more, so definitely worth looking into.
Alternative Solution (edit)
Based on your feedback, my above solution doesn't work since the number is already converted and the decimal part lost when it is passed into the model. A similar piece of code could be used in the controller to intercept and convert the number in the params hash itself:
class PostController < ActionController
before_filter :standardise_numbers, :only => [ :create, :update ]
def create
#post = Post.create(params[:post])
end
protected
# Intercepts the params hash
def standardise_numbers
params[:post][:number].sub!(",", ".")
end
end
This simplifies the create and update methods, allowing you to deal with the hash in the same way you normally would.

I played this it and found this:
Suppose what in form field number, user inputs value '12,13'.
Value from form go to PostController to 'create' method
class PostController < ApplicationController
def create
#post = Post.new(params[:post])
#on this step instance of Post model created, validated and filled with relevant values
#so #post.number == '12' #(decimal), it cuts ',13'
#we need to redefine #post.number
#post.number = params[:post][:number].gsub(/,/,'.').to_f # => 12.13
#and after that save the post
#post.save
end

Related

Ruby on Rails and JSON request processing

I have ruby on rails app and my controller should process request which creates many objects. Objects data is passed from client via json using POST method.
Example of my request (log from controller):
Processing by PersonsController#save_all as JSON
Parameters: {"_json"=>[{"date"=>"9/15/2014", "name"=>"John"},
{"date"=>"9/15/2014", "name"=>"Mike"}], "person"=>{}}
So i need to save these two users but i have some issues:
How to verify strong parameters here? Only Name and Date attributes can be passed from client
How can I convert String to Date if i use Person.new(params)?
Can i somehow preprocess my json? For example i want to replace name="Mike" to name="Mike User" and only then pass it in my model
I want to enrich params of every person by adding some default parameters, for example, i want to add status="new_created" to person params
First of all I'd name the root param something like "users", then it gives a structure that is all connected to the controller name and the data being sent.
Regarding strong params. The config depends of your rails app version. <= 3.x doesn't have this included so you need to add the gem. If you're on >= 4.x then this is already part of rails.
Next in your controller you need to define a method that will do the filtering of the params you need. I should look something like:
class PeopleController < ApplicationController
def some_action
# Here you can call a service that receives people_params and takes
# care of the creation.
if PeopleService.new(people_params).perform
# some logic
else
# some logic
end
end
private
def base_people_params
params.permit(people: [:name, :date])
end
# Usually if you don't want to manipulate the params then call the method
# just #people_params
def people_params
base_people_params.merge(people: normalized_params)
end
# In case you decided to manipulate the params then create small methods
# that would that separately. This way you would be able to understand this
# logic when returning to this code in a couple of months.
def normalized_params
return [] unless params[:people]
params[:people].each_with_object([]) do |result, person|
result << {
name: normalize_name(person[:name]),
date: normalize_date(person[:date]),
}
end
end
def normalize_date(date)
Time.parse(date)
end
def normalize_name(name)
"#{name} - User"
end
end
If you see that the code starts to get to customized take into a service. It will help to help to keep you controller thin (and healthy).
When you create one reason at the time (and not a batch like here) the code is a bit simpler, you work with hashes instead of arrays... but it's all pretty much the same.
EDIT:
If you don't need to manipulate a specific param then just don't
def normalized_params
return [] unless params[:people]
params[:people].each_with_object([]) do |result, person|
result << {
name: person[:name],
date: normalize_date(person[:date]),
}
end
end

Is it possible to compare form submitted strings in array to string values in a model database?

This is more going into rails theory. I want to compare strings submitted by a user to strings in a populated model. Is this possible? Even if it is possible would it be better to create a user in putted model and compare the strings from there?
Is there any documentation on how to achieve this
My names are kind of wonky, I adapted this from a microposts tutorial to try and be a dna(user input) --> rna (mrna db) sequencer (which i understand is very bad form)
users/new.html.erb(renders)/_form.hrml.erb
<%= form_for :user do |t| %>
<%= t.fields_for 'inputdna[]', [] do |p| %>
dna <%= p.text_field :dna %>
<% end %>
<%= t.submit "Submit" %>
<% end %>
user model
class User < ActiveRecord::Base
dna_options = 'ttt, ttc, tta'.split(',')
#validates :dna_options, presence: true
# returns true|false
def dna_valid?(user_input)
user.input.each
return false if unless dna_options.include? user_input
end
return true
end
controllers/users_controller.rb
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.new # not touched, however the convention would normally be User.new
end
def new
User.create(full: params['user']['full'], dna: params['user']['inputdna']['dna'], mrna: params['user']['mrna']) if User.dna_valid? params['user']['inputdna']['dna']
end
end
seed.rb for users model
User.create(full: "phenylalanine", dna: "ttt", mrna: "uuu")
User.create(full: "phenylalanine", dna: "ttc", mrna: 'uuc')
User.create(full: "leucine", dna: 'tta', mrna: 'uua')
It is possible to compare strings, there are few methods to do so, and the difficulty around user inputs that may prove a challenge.
Assuming you had a model such as:
Class SomeStrings
##some_string = 'String Answer'
end
You could compare this to user input from some params like so:
params['user_input'] == SomeStrings.some_string
This will return a boolean (true|false) for use in if/case statements.
Now, to ensure that the inputs match regardless of case you have two simple options:
params['user_input'].downcase == SomeStrings.some_string.downcase
or
params['user_input'].casecmp(SomeStrings.some_string)
http://ruby-doc.org/core-1.9.3/String.html#method-i-casecmp
The latter approach with casecmp is alot faster than downcasing both string parts.
Now in this example I used a class variable ##some_string, however you could apply the same logic to any model with variables/methods that return a string. This model could be an activerecord, or other ORM record, or just a class.
Shout if you want anymore input.
<>
If you wish to pre-populate this model with something on a user by user basis you will need create some level of persistence. This could be in your code 'hard coded', a database or the session. For example, if you want to compare some users input against one of a list of 5 words stored in the session you could do this:
session['words_to_compare_to'] = Words.generate_five_random_words unless session['words_to_compare_to']
you could create a method on your model that creates words, and this would assign them into the session. This means each user would get some words to compare to which are random per user. This could be your method:
class Words
##words_list = 'help, go, north, fred, mimi, the, and, elf'.split(",")
def generate_five_random_words
words_to_return = []
5.times{ words_to_return << ##words_list.sample }
return words_to_return
end
end
Then to compare the input you receive to see if it is within the 5 random words in your controller you could do this:
session['words_to_compare_to'].include? params['user_input'].downcase
We are using downcase here as all of our words list are lower case. This returns a boolean true|false if the user input is found within the array of 5 words. I hope this provides something that you can reuse.
* Update following code addition to question *
I am going to assume that the user fills out the text field and submits it to a route /user/create. I am assuming the purpose is to check that the 3 letter dna that the user submitted is within an acceptable dna list.
So to start, lets add the acceptable dna combinations to the user model:
Class User
dna_options = 'ttt, ttc, tta'.split(',')
# returns true|false
def self.dna_valid?(user_input)
dna_options.include? user_input
end
end
Now, depending on which ORM you are using, you can also use validators for this: http://guides.rubyonrails.org/active_record_validations.html
To use the above within your controller you could do this:
class UsersController < ApplicationController
def index
#users = Array.new # not touched, however the convention would normally be User.new
end
def create
User.create(full: params['user']['full'], dna: params['user']['inputdna']['dna'], mrna: params['user']['mrna']) if User.dna_valid? params['user']['inputdna']['dna']
end
end
Now, I have made lots of assumptions here, as your code is missing the same entities as your model, however I hope you see what can be done. If params['user']['inputdna'] returns an array, you could change the code to:
if user.dna_valid? params['user']['inputdna']
and change the boolean operator within the model to:
# returns true|false
# expects user_input to be an array
def self.dna_valid?(user_input)
user.input.each do |dna|
return false if unless dna_options.include? dna
end
return true
end
This returns true if all the entities are found within the dna_options, or false if one of them does not
If you're looking for only comparing and finding exact matches, then this is what I used.
all_users = params[:user][:dna].map do |u|
User.find_by(name: u)
end
Here you're getting the response from the form submission in the "params[:user]", then it is comparing that response to the User table using the "User.find_by(name: u)" and assigning matches to "all_users" through the map loop.
The problem you might encounter here is if the form submission does not find an entry in the model, which will then return a "nil". This simple logic does not deal with "nil" returns.

Ruby - How to define params for require()?

questions_controller.rb
def index
#questions = Question.all(app_params)
end
private
def app_params
params.require(:questions).permit(:question, :answer)
end
end
question.rb
class Question < ActiveRecord::Base
end
I am completely new to ruby-on-rails. I was following a guide and it said I should take care of some "loopholes" or "security issues" and it used attr_accessible, but on Rails 4, they suggest strong parameters, so now I'm trying to use them. I'm confused on how to define the :questions params, because I'm currently getting an error saying that :questions param is not found.
:questions is pretty much something that I will define myself as the web developer.
So for example, I will define questions = "How are you?", "What is your name?". I'm basically starting very simply. I want questions that I have created to be displayed on my webpage. Ultimately, I plan to make a website what is basically a list of questions and, with answer options. After the user clicks "submit" I want to store the information into my database.
Am I supposed to even be requiring this as a param? I'm completely lost..
Do you have a dump of the params we could look at? They are shown when your app encounters an error, and typically shows you the params array which rails will pass through
Strong Params In Rails 4
Strong Params allow you to allow certain parameters for use in the controller, protecting against any malicious assignment client-side. They replaced attr_accessible in Rails 4.0
Strong Params is only for user-submitted content, as it's designed to protect the params hash. To that end, it's mostly used with the create and find functions:
class PeopleController < ActionController::Base
# Using "Person.create(params[:person])" would raise an
# ActiveModel::ForbiddenAttributes exception because it'd
# be using mass assignment without an explicit permit step.
# This is the recommended form:
def create
Person.create(person_params)
end
# This will pass with flying colors as long as there's a person key in the
# parameters, otherwise it'll raise an ActionController::MissingParameter
# exception, which will get caught by ActionController::Base and turned
# into a 400 Bad Request reply.
def update
redirect_to current_account.people.find(params[:id]).tap { |person|
person.update!(person_params)
}
end
private
# Using a private method to encapsulate the permissible parameters is
# just a good pattern since you'll be able to reuse the same permit
# list between create and update. Also, you can specialize this method
# with per-user checking of permissible attributes.
def person_params
params.require(:person).permit(:name, :age)
end
end
params.require
The params.require function works by taking this params hash:
params{:question => {:question => "1", :answer => "5"}}
That's why people asked what your params hash looks like, because the require function can only work if the :question hash is present.
Possible Solutions For You
Question.all(app_params)
Regardless of what you're trying to achieve, don't use all. The where function is better for receiving an array of data based on certain values. I believe all is depreciated anyway.
def index
#questions = Question.where("value = ?", variable)
end
What data is being passed?
I will define questions = "How are you?", "What is your name?"
This is okay, but typically in rails, you'd call data by using an ID in the database. If you're defining these questions in a form, you'd use the strong params system; but you'd need a form to submit the data to
Further Additions
The rails way is to keep all your data in a database, and use the application to manipulate that data, either by showing it, or allowing people to input more.
The "params" variables are basically there to help the rails controllers & models accept & process data from end users, and consequently allow you to keep the system growing. Instead of having to write custom code to accommodate all sorts of different data, the params give you a rigid structure to work with. Here is a good explaination of how MVC (and params) works for you: How does an MVC system work?
I think you're getting confused with how your app should work
Your "questions" should be stored in a questions table / model, and can be accessed by calling their ID's with the find function. This code would be like this:
#app/controllers/questions_controller.rb
def show
#question = Question.find(params[:id])
end
If you want to add new questions, you'll be best to add them to the questions table, like this:
#app/controllers/questions_controller.rb
def new
#question = Question.new
end
def create
#question = Question.new(question_params)
#question.save
end
private
def question_params
params.require(:question).permit(:question)
end
#app/views/questions/new.html.erb
<%= form_for #question do |f| %>
<%= f.text_field :question %>
<% end %>
This will give you a central store of your questions, which you'll then be able to access when you need them, either with a helper or with your ".all" call :)
Give it a shot with question (singular):
params.require(:question).permit(:text, :answer)
Assuming question is your model and text (which I made up) is the wording of the question.

Using Rails model to update to change one boolean value based on another

I'm trying to make a pet rails app. My pet model includes two boolean values, hungry and feed_me. Right now, hungry and feed_me can both be set in the view, but I'm trying to set up the model so that if feed_me is true, hungry will automatically be changed to false. No matter what I do, however, feed_me never resets hungry. This is what I have in the model now:
attr_accessor :feed_me
before_save :feed
def feed
#feed_me = Creature.find(params[:feed_me])
#hungry=Creature.find(params[:hungry])
if #feed_me==true
#hungry=false
end
end
I'm new to Rails, but my understanding is that model should have access to the params hash, so I'm confused about why I can't use it to reset values.
You're on the right track using model callbacks, however models don't have access to the param hash - its available to controllers.
The model already knows the value of it's own attributes, so you don't need to get them from params. The controller I imagine is updating feed_me.
Also you shouldn't need to declare feed_me as an attr_accessor assuming it is backed by a database column.
You can change before_save to:
def feed
if self.feed_me
self.hungry = false
end
end
In your controller, I imagine you'd do something like:
def update
pet = Pet.find(params[:id])
pet.feed_me = params[:feed_me]
if pet.save
redirect_to pet_path(pet)
else
flash[:notice] = 'Error saving pet'
render :edit
end
end

update_attributes field tweaks

So I've got an edit page that has butt-load of editable fields on it...simple update...
#patient.update_attributes(params[:patient])...everything's great, except....
I've got one field out of these 20 that I need to tweak a little before it's ready for the db and it would seem I either need to do
two trips
#patient.update_attributes(params[:patient])
#patient.update_attribute( :field=>'blah')
or set them all individually
patient.update_attributes(:field1=>'asdf', :field2=>'sdfg',:field3=>'dfgh', etc...)
Am I missing a way to do this is one swoop?
What's the attribute you need to tweak? There's two ways to do this:
Either massage the params before you send them to the update_attribute method:
I'm just giving an example here if you wanted to underscore one of the values:
params[:patient][:my_tweak_attribute].gsub!(" ", "_")
#patient.update_attributes(params[:patient])
Then there's the preferred way of doing your tweaking in a before_save or before_update callback in your model:
class Patient < ActiveRecord::Base
before_update :fix_my_tweak_attribute, :if => :my_tweak_attribute_changed?
protected
def fix_my_tweak_attribute
self.my_tweak_attribute.gsub!(" ", "_")
end
end
This keeps your controller clean of code that it probably doesn't really need.
If you just need to add a new param that didn't get sent by the form you can do it in the controller like this:
params[:patient][:updated_by_id] = current_user.id
#patient.update_attributes(params[:patient])
Assuming current_user is defined for you somewhere (again, just an example)
You can create a virtual attribute for that field. Say the field is :name. You create a function in your Patient model like :
def name
self[:name] = self[:name] * 2
end
And of course, you do your things inside that function :) Instaed of self[:name], you can also use read_attribute(:name).

Resources