Is there a way I can avoid the hidden_field
method of passing values in the view to a controller? I would prefer a controller method for security reasons. Unfortunately value pairing @variables
is not supported in strong_parameters
.
EDIT 6/18 1:00 PM EST
- I've renamed my
garages
controller toappointments
cars_controller
no longer creates a newappointment
(formallygarages
). A new appointment is created in theappointments_controller
My current structure
routes
Rails.application.routes.draw do
resources :techs, only: [:index, :show], shallow: true do
resources :cars, only: [:new, :create]
end
resources :appointments
#For searchkick
resources :cars, only: [:show] do
collection do
get 'search'
end
end
root "home#index"
end
models
tech.rb
class Tech < ActiveRecord::Base
searchkick
has_many :appointments
has_many :customers, :through => :appointments
has_many :service_menus
has_many :services
has_many :cars
end
service.rb
class Service < ActiveRecord::Base
belongs_to :tech
belongs_to :service_menu
has_many :cars, dependent: :destroy
accepts_nested_attributes_for :cars, :reject_if => :all_blank, :allow_destroy => true
end
car.rb
class Car < ActiveRecord::Base
belongs_to :service
belongs_to :tech
has_many :appointments
end
appointment.rb
class Garage < ActiveRecord::Base
belongs_to :customer
belongs_to :tech
belongs_to :car
end
controllers
cars_controller
def new
@car = Car.find(params[:id])
@tech = Tech.find(params[:tech_id])
@appointment = Garage.new
end
appointments_controller
def create
@appointment = current_customer.appointments.build(appointment_params)
if @appointment.save
redirect_to appointments_path, notice: "You car has been added to this appointment."
else
redirect_to appointments_path, notice: "Uh oh, an error has occured."
end
end
private
def appointment_params
params.require(:appointment).permit(:tech_id, :service_id, :car_id, ...and a bunch of other keys here)
end
views
cars.new.html
Please note this form passes hidden values to the
appointment_controller
.Value from
@car.name
and other alike are not from atext_field
but rather a pre-defined value based on selections from a previous page which is store in thecars
db.
<%= simple_form_for(@appointment, { class: 'form-horizontal' }) do |f| %>
<%= f.hidden_field :tech_id, value: @tech.id %>
<%= f.hidden_field :car_id, value: @car.id %>
<%= f.hidden_field :service_id, value: @car.service.id %>
<%= f.hidden_field :customer_car, value: current_customer.car %>
<%= f.hidden_field :customer_street_address, value: current_customer.street_address %>
<%= f.hidden_field :customer_city, value: current_customer.city %>
<%= f.hidden_field :customer_state, value: current_customer.state %>
<%= f.hidden_field :customer_zip_code, value: current_customer.zip_code %>
<%= f.hidden_field :service_name, value: @car.service.service_menu.name %>
<%= f.hidden_field :car_name, value: @car.name %>
<%= **And a bunch of other hidden values here which are too long to list** %>
<%= f.submit "Add to appointment", class: 'btn btn-default' %>
<% end %>
service.html
<%= render 'form' %>
_form.html
<%= simple_form_for @service do |f| %>
<div class="field">
<%= f.label "Select service category" %>
<br>
<%= collection_select(:service, :service_menu_id, ServiceMenu.all, :id, :name, {:prompt => true }) %>
<%= f.fields_for :cars do |task| %>
<%= render 'car_fields', :f => task %>
<% end %>
</div>
<div class="links">
<%= link_to_add_association 'Add New Car', f, :cars, class: 'btn btn-default' %>
</div><br>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
_car_fields.html
<div class="nested-fields">
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= f.label :hours %>
<%= f.select :hours, '0'..'8' %>
<%= f.label :minutes %>
<%= f.select :minutes, options_for_select( (0..45).step(15), selected: f.object.minutes) %><br>
<%= f.label :price %><br>
<%= f.text_field :price, :value => (number_with_precision(f.object.price, :precision => 2) || 0) %> <br>
<%= f.label :details %><br>
<%= f.text_area :details %></div>
<%= link_to_remove_association "Remove Car", f, class: 'btn btn-default' %>
<%= f.hidden_field :tech_id, value: current_tech.id %>
<br>
<hr>
</div>
> Edit 7/14 1:30 pm EST
Brief Synopsis on this specific function of the application
customer
clicks through a list of services a tech
has to offercustomer
selects a service for example brakes which is a service a tech
has listed in his profile.cars
dbcars
belongs_to
to techs
customer
can save brakes which is an attribribute of a techs
car
to a appointment
tech
, the customer
's street address, etc..., and the car
are pre-loaded in the form
for storing in the appointments
table.appointment
acts as a histories table. So if the tech
decides to modify any one of his services
in this example brakes, the appointments
tables will remain untouched for the brakes entry.customer
selects the Add to appointment
button, it will save all of the predefined values from tech
, customer
, and car
attributes (in this example brakes) to the appointments
db.Another approach to this would be to get rid of the strong parameters
altogether and do the following:
def create
@appointment = Garage.create(tech_id: @car.service.tech.id,
customer_id: current_customer.id,
customer_street_address: current_customer.street_address,
customer_city: current_customer.city,
customer_state: current_customer.state,
customer_zip_code: current_customer.zip_code,
customer_phone_number: current_customer.phone_number,
customer_location_type: "WILL ADD LATER",
customer_latitude: current_customer.latitude,
customer_longitude: current_customer.longitude,
service_id: @car.service.id,
service_name: @car.service.name,
car_id: @car.id,
car_name: @car.name,
car_time_duration: @car.time_duration,
price: @car.price,
car_details: @car.details)
if @appointment.save
redirect_to techs_path, notice: "This service has been saved."
elsif
redirect_to tech_path, notice: "Uh oh, an error has occurred."
end
end
Please let me know if you require further details.
I can think of some methods you could use to avoid this form
bloated with hidden_field
s:
hidden_field
in the form
.Whichever method you choose, keep in mind that storing a lot of state in a web application usually is a code smell. You can always rethink your application so you don't need to keep so much context.
To resolve my issue, my latest edit from my initial post stated the following:
EDIT 6/18 1:00 PM EST
- I've renamed my
garages_controller
toappointments_controller
cars_controller
no longer creates a new appointment (formally garages). A new appointment is created in theappointments_controller
Only hidden_field i'm passing is the car_id
in the appointments view /new.html.erb <%= f.hidden_field :car_id, value: @car.id %>
.
In the appointments_controller
, I'm assigning all the car
attributes doing the following.
def create
@appointment = current_customer.appointments.build(appointment_params)
@appointment.tech_id = @appointment.car.service.tech.id
@appointment.price = @appointment.car.price
@appointment.car_name = @appointment.car.name
@appointment.car_details = @appointment.car.details
if @appointment.save
redirect_to appointments_path, notice: "Thank you booking your appointment."
else
redirect_to appointments_path, notice: "Uh oh, an error has occurred. Please try again or contact us for further assistance"
end
end
Thank you all for your responses. I should've known better. :(
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With