I have a form in rails with input values, and 1 of the values is a LOV (List of Values) and a second input field is also a LOV but depends on the input of the other field.
The input value of the first field is not saved in between. So I need to use that field value before it is saved.
So, the example:
I choose a company from the list of values of all companies for the field supplier, the second field supplier_address will be a LOV with all the addresses of that company, so the LOV of the second field is dependent on the value chosen in the first field, company.
What I tried:
def new
#purchase_requisition = PurchaseRequisition.new
#purchase_requisition.number = find_next_user_value("Purchase_Requisition")
##purchase_requisition.supplier_address_id = PurchaseRequisition.new.purchase_requisition_params[:supplier_id]
#purchase_requisition = PurchaseRequisition.new(purchase_requisition_params)
respond_to do |format|
#purchase_requisition.supplier_address_id = PurchaseRequisition.new.purchase_requisition_params[:supplier_id]
end
end
but I still get the error:
param is missing or the value is empty: purchase_requisition
Can someone please help me?
Thank you!!!
The error you're encountering isn't being caused by the code you've provided. You're probably using strong parameters and have a method like this:
def purchase_requisition_params
params.require(:purchase_requisition).permit(# some list of attributes #)
end
The problem is that params[:purchase_requisition] doesn't exist. Probably because the form_for in your view isn't referencing a purchase_requisition object. Try adding as: to your form_for to send your params under that param key:
form_for #requisition, as: :purchase_requisition, ....
Otherwise, you'll have to post more details about your view and controller to help isolate the issue you're having.
Also, in your controller code you want:
PurchaseRequisition.new(purchase_requisition_params[:supplier_id])
Instead of:
PurchaseRequisition.new.purchase_requisition_params[:supplier_id]
Supposing, all of your parameters belong to the same object (there isn't any nested attribute), this can be what you are looking for:
def purchase_requisition_params
params.require(:purchase_requisition).permit(:org_id, :document_type, :number, :supplier_id, :supplier_address_id, :partner_id, :project_id, :construction_site_id, :purchase_order_date, :expected_receiving_date, :promised_receiving_date, :supplier_order_number, :supplier_shipping_number, :supplier_invoice_number, :currency, :status) ##you don't need id here
end
Related
I recently started with rails.
I have one task here, but I don't know what is best practice and how to do it.
I have form with checkbox currency? and input currency_code.
Only value currency_code will be stored in database.
What I need:
1. If checkbox currency? is TRUE => currency_code must be filled
2. If checkbox currency? is FALSE => currency_code will be reset to nil
How to validate 1. if currency? is not in database (table column) so model does not know about this?
In case 2. Where I should check this and reset value currency_code to nil?
For case 2. I have this in my controller, but I don't like. I think that there must be a better solution.
def data_params
parameters = params.require(:data).permit(
:currency_code
)
parameters[:currency_code] = nil unless params[:data][:currency].to_bool
parameters
end
The attribute 'currency?' which is not part of the model is called virtual attributes. In Rails, we can use virtual attributes by setting
attr_accessor :currency?
in your corresponding_model.rb.
Now you can use this 'currency?' attribute in your form like other model attributes.
For case 2, the plcaement for this kind of data validations is to validate them in the view before even coming into the model. you must use jquery / javascript or any script of your choice. Here I provide jQuery snippet.
If you are new for using jquery in rails app, follow this https://github.com/rails/jquery-rails
In your form_page.html.erb add ids to the html elements.
<%= f.check_box :currency?, id: 'currency_checkbox' %>
and
<%= f.text_field :currency_code, id: 'currency_code' %>
The jquery snippet
curreny_checkbox = $('#curreny_checkbox')
currency_code = $('#currency_code')
$(currency_checkbox).on('change', function(){
if(this.checked)
currency_code.val('2')
else
currency_code.val('')
})
In your controller, you can simply assign the values
def create
// other codes //
#obj.currency_code = params[:currency_code]
end
If you want to validate input on model level you should store the currency? in the database.
Still let say for some unexplained reasons you don't want to store currency? in you database(which I won't suggest you in any case). You can define a method in model.
def set_currency_if_required is_currency_required
self.currency_code = nil unless is_currency_required
end
in controller
def create
model = Model.new(data_params)
model.set_currency_if_required(params[:data][:currency].to_bool)
model.save
end
...
def data_params
parameters = params.require(:data).permit(
:currency_code
)
end
this way you will have better readability and a clear idea about whats going on with the code.
If there is value in marital_status then prompt should not be displayed but in my case it's displaying. My code is mentioned below. Please help.
= select_tag( 'request[marital_status]',
options_for_select(marital_status_options,
#employee.marital_status.try(:upcase)), prompt: "Select Marital Status", id: 'employee_marital_status', disabled: #request.submitted?)
In employee_helper.rb
def marital_status_options
Employee::MaritalStatus::ALL.zip(Employee::MaritalStatus::ALL)
end
In employee model
module MaritalStatus
MARRIED = 'MARRIED'
SINGLE = 'SINGLE'
DIVORCED = 'DIVORCED'
ALL = [MARRIED, SINGLE, DIVORCED]
end
You're very close. The problem here likely stems from your marital_status_options method: this will simply return DIVORCED as it evaluates to the last line due to your assignment.
Therefore, you might find the value is selected if your instance contains 'DIVORCED', though not either of the other values; your instance's value needs to match one of these for it to be selected instead of the prompt.
You likely want to change this:
def marital_status_options
MARRIED = 'MARRIED' # this will be evaluated first
SINGLE = 'SINGLE' # then this
DIVORCED = 'DIVORCED' # finally, this will be evaluated and returned as 'DIVORCED'
end
To an array, either:
def marital_status_options
['MARRIED', 'SINGLE', 'DIVORCED']
end
Or, to present the options as lowercase but keep uppercase values in the db:
def marital_status_options
[['Married', 'MARRIED'], ['Single', 'SINGLE'], ['Divorced', 'DIVORCED']]
end
Take a look at the docs on options_for_select and you'll see who they can be setup.
Further down the line, you might want to consider switching to enums - these are very handy for managing selections such as these, and auto generate methods such as Employee.married, employee.divorced?, and so forth.
As someone else has mentioned, it's best practice to store data such as this in the relevant model, though I'd argue these should be stored as a constant as they won't be changing. So one of the following:
# employee.rb
MARITAL_STATUSES = ['MARRIED', 'SINGLE', 'DIVORCED'].freeze
# or
MARITAL_STATUSES = [['Married', 'MARRIED'], ['Single', 'SINGLE'], ['Divorced', 'DIVORCED']].freeze
= select_tag('request[marital_status]',
options_for_select(Employee::MARITAL_STATUSES,
#employee.marital_status.try(:upcase)),
prompt: "Select Marital Status",
id: 'employee_marital_status',
disabled: #request.submitted?)
Hope that helps - let me know if you've any questions or need anything else.
The format and usage is correct. Kindly verify if #employee.marital_status.try(:upcase) exactly matches one of the marital_status_options provided here.
That looks like a probable case for such a behaviour.
Also, the first argument expected in select_tag needs to in an appropriate format, in this case, an array of strings.
Hence, your method marital_status_options should return an array of options to be used for dropdown.
def marital_status_options
['MARRIED', 'SINGLE', 'DIVORCED']
end
= select_tag "request[marital_status]", options_for_select(Employee.marital_status_options,
#employee.marital_status.try(:upcase)), :include_blank => '--Select Marital Status--', id: id: 'employee_marital_status', disabled: #request.submitted?
It's a good practice to define marital_status_options(Business logic) inside model: -
Assuming that it's Employee model
def self.marital_status_options
[
["MARRIED","MARRIED"],
["SINGLE","SINGLE"],
["DIVORCED", "DIVORCED"]
]
end
Reason that it's not selecting your default marital_status is because if #employee.marital_status.try(:upcase) will not match any of the marital_status_options, it will show your prompt option, so check it carefully that if #employee.marital_status.try(:upcase) matches any of the given options of select tag's option.
Through an API my models get updated with this call:
if #user.update_attributes(params.permit(:name, :phone, ...)
format ...
else
format ...
end
This is nested in another if query and based on the result i would like to set a another variable in the same model. So far i do it with
#user.update_attributes(variable: :value)
But this issues two writes on my table, which i am pretty sure can be
merged into one, but i don't know how.
This is the whole block:
if test_for_something
#user.update_attributes(variable: :value)
if #user.update_attributes(params.permit(:name, :phone, ...)
format ...
else
format ...
end
Thanks all in advance!
add the value into the permit hash and then run update_attributes only once.
just make sure this field is permitted.
this is just an example how u can do it:
EDIT:
params[:value] = value
if in nested in the model name then:
params[:model][:value] = value
then:
#user.update_attributes(params.permit(:name, :phone, :value, ...)
hope it helped you.
I'm trying to find the value of a particular model's attribute in rails. Here's what my code in the User controller's 'create' method looks like:
#user = User.find(1, :select => :money)
existing_money = #user
puts "#{existing_money}"
In my Heroku logs I'll see a variant of the following output instead of the :money integer for that particular user (with :id 1)
#<User:0x00000004e7cbc0>
Any thoughts? Thanks!
#user = User.find(1, :select => :money)
You are setting the #user instance variable with an object that has only one value, namely the money value. For now, all this does is save you a few bytes, by leaving off things like id, email, and any other columns you have in that table. It does however still return an object with attributes, the only difference is your object has only one attribute to call.
existing_money = #user
Given that #user is still an object with a single attribute, you now save this object in the existing_money local variable. What you probably want to do is *only store the money attribute in this variable`.
So you'd need this:
existing_money = #user.money
puts "#{existing_money}"
After the above change, this puts statement should return the attribute value, not the object encapsulating the attribute.
As existing_money is just the object you are seeing the object's ID.
As you want the money attribute you have to reference that too.
puts "#{existing_money.money}"
I cant see what im missing. I have and Order with nested Items, these Items each have a Kind. I want to manipulate the kind_id param from each Item but the "f[:kind_id]" always return 0.
#order.items.each do |f|
f[:kind_id] = Kind.find_by_name(f[:kind_id]).id
end
the params i get is
{"authenticity_token"=>"7wz7ARjwcVvCR/bpp/T04JQIQwHsMKDflF1eMCL8PTU=",
"order"=>{"items_attributes"=>{"1271160144889"=>{"price"=>"2",
"amount"=>"2",
"text"=>"2",
"kind_id"=>"fds",
"_destroy"=>""}},
"total_price"=>"4"}}
The above params is of course test data :)
Because :kind_id is an integer column, ActiveRecord is automatically interpreting it as an integer for you ("fds".to_i #=> 0). You should add attr_accessor :kind_name to the Item model and switch the form field to kind_name. Then you can do
#order.items.each do |f|
f.kind = Kind.find_by_name(f.kind_name)
end