How to send user.id with :user in params even though user.name is what is in the form drop down? - ruby-on-rails

Currently, I have an action in my customers controller generating an array of names, #username_array, of all objects of class User with which to populate a drop down menu in a form that creates a new object of class Customer. The form element looks like this right now:
<%= f.select :user_id, #username_array %>
What I'd really like is for the id of the user to be sent into params[:customer][:user_id] instead of the name of that user that is chosen in the drop down. So in my create action in my customers controller I have the following code:
#customer = Customer.new(params[:customer])
#user = User.find_by_name(params[:customer][:user_id]) # where :user_id is actually currently the name selected from the drop down
#customer.user_id = #user.id
Is there an easier way of doing this?

Change your #username_array to include both the name and the id of the user:
Instead of:
["Bob","Sally","Dave"]
Make it:
[["Bob", 1],["Sally",2],["Dave",3]]
This could be accomplished by something like this:
#username_array = User.all.map {|user| [user.name, user.id]}
Then, f.select will display the name in the dropdown, but the actual value passed in through params[:customer][:user_id] will be the id of the user, which is what you want. With this in place, the following is all you need in the controller action code:
#customer = Customer.new(params[:customer])
You won't have to look up the user by name, the params hash will already have the correct id value.
Note that instead of making #username_array an instance variable you could just create a utility method in the helper for this controller, or the application helper:
def user_select
User.all.map {|user| [user.name, user.id]}
end
Then, in your view:
<%= f.select :user_id, user_select %>
If you put this in your application helper, you can use it everywhere and only have the code in one place (DRY).

you can do
#user = User.find_by_name(params[:customer][:user_id])
#user.customers.new(params[:customer])
or
#user = User.find_by_name(params[:customer][:user_id])
#customer = #user.customers.create(params[:customer])
but to do that you must have the relation (has_many, belongs_to,...)
or
Customer.new(params[:customer], :user_id => params[:customer][:user_id])
or
f.collection_select :user_id, #username_array, :id, :name

Related

ActiveAdmin passing variable in controller

I have a permit and vehicle model. I am trying to update the AA create controller to work how I have it in my rails app. That is taking the vehicle license_number entered and inputting it into the permit table, then also taking the inputted permit_id and inputting it into the permits attribute of the vehicle it is related to in the vehicle table.
admin/permit.rb
permit_params :permit_id, :vehicle, :date_issued, :issued_by, :date_entered, :entered_by
form do |f|
f.inputs do
f.input :permit_id
f.input :vehicle, :collection => Vehicle.all.map{ |vehicle| [vehicle.license_number]}
f.input :date_issued, as: :date_picker
f.input :issued_by
end
f.actions
end
controller do
def new
#permit = Permit.new
#vehicle = #permit.build_vehicle
#vehicle = Vehicle.all
super
end
def create
vehicle = Vehicle.find_by(license_number: permit_params[:vehicle_attributes][:license_number])
#permit = current_user.permit.build(permit_params.merge(date_entered: Date.today,
entered_by: current_user_admin.email))
super
end
end
My errors that I am getting, is that it is inputting the license_number in for the permit_id and then it is also saying the permit_params is not a defined variable. Any help would be great, thanks!
You have an interesting case here: it is confusing because you have a model called Permit, and usually in Rails you name the params method something like permit_params. Turns out, permit_params is the general method signature for ActiveRecord to implement strong params: https://activeadmin.info/2-resource-customization.html
With that, instead of calling permit_params in your create action, you need to call permitted_params[:vehicle_attributes][:license_number]. That’s why it’s considering permit_params as an undefined variable. Again, those two method signatures will be the same for all your ActiveAdmin forms.
Additionally, I’m not sure if this is a typo but you define #vehicle twice in your new method. I’m not sure you need to build a vehicle for the permit form unless you’re doing nested forms. Either way, I think the last line should read #vehicles = Vehicle.all Then you can use that in your form, which also could use an update in the collection part of your form field:
form do |f|
f.inputs do
f.input :permit_id
f.input :vehicle, collection: #vehicles.map { |vehicle| [vehicle.license_number, vehicle.id] }
f.input :date_issued, as: :date_picker
f.input :issued_by
end
f.actions
end
The collection_select form tag will take the first item in the array as the value that appears in the form, and the second value will be the value passed through in the params (https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/collection_select).
Then in your create action, you can find the Vehicle with the id:
Vehicle.find(permitted_params[:vehicle_attributes][:vehicle_id])
I would avoid Permit as a model name, try using VehiclePermit.

getter not getting values for new record on validation rails 4

I have a form_for for creating a new record. I have set getter and setter methods to access form field in my view. Below are my getter ans setter methods with my form view,
Getter & Setter Methods respectively :
def manufacturer_model_name
self.manufacturer_models.pluck(:name).join(', ') unless self.manufacturer_models.blank?
end
def manufacturer_model_name=(names)
names = names.split(',').map{|n| n.strip}.delete_if(&:empty?) if names.present?
names.uniq.each do |name|
id = ManufacturerModel.where(:name => name, :manufacturer_id => manufacturer.id).first_or_create.id
if self.new_record?
self.user_skill_manufacturer_models.build(:user_skill_id => self.id, :manufacturer_model_id => id)
else
self.user_skill_manufacturer_models.where(:user_skill_id => self.id, :manufacturer_model_id => id).first_or_create.id
end
end if names.present?
end
Form View:
= f.text_field :manufacturer_model_name, :class => 'form-control
My problem is that, my input field is autocomplete with multiple set to true, to get multiple values. when user enters multiple comma separated values and submits form and if there are any errors on the form, my new action is rendered and user losts all the entered values forcing him to reenter all again. How can I solve this problem?
It would be better to make a manufacturer_model_name_form field or some such via attr_accessor, and then parse that in validate. It would look something like this:
class ManufacturerModel < ActiveRecord::Base
attr_accessor :manufacturer_model_name_form
validate :validate_manufacturer_model_name
def validate_manufacturer_model_name
errors.add(:manufacturer_model_name, 'not a valid manufacturer model name') if !!true # perform your validation here in place of `!!true`
end
end
Then, in your form, you would use manufacturer_model_name_form instead of manufacturer_model_name:
= f.text_field :manufacturer_model_name_form, :class => 'form-control'

Have a select box filled with names

In my view I have a form with a text_field_tag that takes an int, and returns only the timesheets whose timesheet.user_id match that int
<%= text_field_tag("user_id", params[:user_id]) %>
And then I have a bunch of users, these users have a name user.name and an id user.id.
I have a method in the controller called pending_approvals that when given the user id, narrows my list down to a specific users objects.
if params[:user_id].present?
#time_sheets = #time_sheets.joins(:user).where("users.id IN (?)", params[:user_id])
end
So what I am having an issue with, is I am not sure how to populate my select box with a list of users names. And then when submitted I need it to give the users id to that method. What is the best way of doing this?
If I understand correctly is you want a collection dropdown list to detail all users and thier id. You can do:
<%= collection_select :user, :user_id, #users, :name, :id, :prompt => true %>
Where :text_method is method which called on #users members will return text that you'd like to appear in dropdown.
The ApiDocs breaks it down, and this is how it is set up:
object = User
method = user_id
collection #users
value_method = id
text_method = name
option = prompt => true

Rails nested form with accepts_nested_attributes_for with an unfortunate model name

I have a Parent model named "Controller" (Mature app, and not my decision)
belongs_to :controller
accepts_nested_attributes_for :controller
Form:
= f.fields_for :controller do |c|
= c.hidden_field :id, :value => #controller.id
= c.text_field :slw_type
which doesn't get displayed.
= f.fields_for :literally_anything_else do |c|
= c.hidden_field :id, :value => #controller.id
= c.text_field :slw_type
if change the variable name to anything else, the form builds. I have a hunch that it's a rails specific reserved name.
Question:
What's the problem? and how can I make this work?
SOLVED:
The issue was that the parent model wasn't associated with the child model yet. My mistake for not providing all the information necessary.
This worked.
def new
#controller = Controller.find(params[:controller_id])
#inspection = Inspection.new(:controller => #controller)
Therefore my fields_for form builder also worked.
Pick some innocuous variable name. not_really_a_controller or whatever. Use that for your variable and your form. Then, in your actual controller (e.g. ActionController::Base descendent), rename the incoming param so the model doesn't know any different, like so:
before_filter :filter_params
private
def filter_params
if params[:not_really_a_controller]
params[:controller] = params.delete(:not_really_a_controller)
end
end
I've used this strategy for similar reasons in the past, though not specifically for controller. Worth a try though!

Passing IDs through a new Form

This question is about a different approach I'm trying to the one asked here:
Passing IDs through a new Form
I have a group#view page, that is accessed by a Person. In this page, the Person can see the members of the group via methods I developed. The problem is that I need to create the model Honors using the Id from the group, the id from the person accessing the page, and the id from a member of this group.
In my Honors controller I have:
def create
#person = Person.find(current_person)
#asked_groupmembership = #person.owned_group_memberships.find_all_by_status(true,:include => [:group, :member])
#asked_groupmembership.each do |agm|
#honor = Honor.create(:group => Group.find(params[:group_id]),
:person => Person.find(current_person), :honored => Person.find(agm.member.id))
end
if #honor.save
...
end
In my view I have a link that directs the person to the form in order to create a new honor:
<% #asked_groupmembership.each do |agm| %>
<%= link_to "Create Honor", new_honor_path(:group_id => #group.id, :person => current_person.id,
:honored => agm.member.id) %>
But in my forms I can't get the ids and stuff
<% form_for(:honor, :url => honors_path(:group_id, :person,
:honored)) do |f| %>
The error I get is that I can't find Group without an Id.
Any ideas? Thanks.
##Edited2##
Changed my crontroller
def new
##person = Person.find(params[:person])
##honored = Person.find(params[:honored])
##group = Group.find(params[:group_id])
#honor = Honor.new
end
def create
#person = Person.find(current_person)
#honor = Honor.create(:group => Group.find(params[:group_id]),
:person => Person.find(params[:person]),
:honored => Person.find(params[:honored]))
if #honor.save
...
end
First, it seems like you are missing a controller method. Along with every form that creates a new object there are typically two controller methods
new
Gathers up any data that the form needs to render itself
Renders the form
create
Collects the data from the form
Creates the new object
It looks to me like you are missing the new method. In the new method you would gather up all the hidden data that the form needs (e.g. the information that the user is not going to type in directly, like the #person info). Then, I would put this information in your form using hidden form parameters (rather then trying to put it in the form URL).
Objective: From the group#view, loop through and create and "Add Honor" link for each member of the group, while keeping track of the specific member being honored, group in which said member is honored, and the person who is honoring.
The following accomplishes that objective.
Route:
match "honors/:group/:person/:honored" => "honors#create", :as=>"my_custom_new_honor"
Group view:
<% #asked_groupmembership.each do |agm| %>
<%= link_to "Create Honor", my_custom_new_honor_path(:group=> #group.id, :person => current_person.id,:honored => agm.member.id) %>
Honor Controller, Create Method
#honor = Honor.create(:group => Group.find(params[:group_id]),
:person => Person.find(params[:person]),
:honored => Person.find(params[:honored]))
In this scenario you do not need the honor#new method, you're going directly to the create method. This assumes all the relationships are established correctly.

Resources