Reputation: 203
Booking model belongs_to DiscountCode. The booking form has a string input for discount_code, which is turned to DiscountCode in the controller:
updated_params = booking_params
if updated_params[:discount_code]
updated_params[:discount_code] = DiscountCode.find_by code: updated_params[:discount_code]
end
@booking = Booking.new(updated_params)
So right now if the code entered does not exist, updated_params[:discount_code] is nil, which is the same as if no discount code was entered. I would rather add an error to @booking.discount_code in that if statement, but I'm in the controller, is that possible?
Upvotes: 0
Views: 1758
Reputation: 32933
The solution to this sort of thing is generally to do something very simple, standard, agnostic and scaffoldy with @booking in the controller, like @booking = Booking.new(params[:booking])
or @booking.update_attributes(params[:booking])
. Always try to keep your controller methods as standard as possible and push logic into the models and data into the views.
So, that leads us on to passing the discount code through via a Booking setter method. If we don't have that setter method already from Rails, then we need to add it. Let's assume that there's already an association like "has_one :discount_code" in Booking. We can write a setter method to make this association from the code, and validate it like so.
(note that it's confusing to have a field called "code" in a class called "DiscountCode" - you're going to be writing @discount_code.code
which begs the question "is a 'code' a string of letters and numbers like '12dafj1213', or is a 'code' an ActiveRecord object loaded out of the database?". I'd recommend either renaming the class to "Discount" (so you would say @discount.code) or renaming the "code" field to "token" (so you would say @discount_code.token). I haven't addressed this issue in my solution, i've stuck with your naming, so my code looks quite confusing with all the "code_code" stuff.
class Booking
attr_accessor :discount_code_code
has_one :discount_code
before_validation :set_discount_code_from_discount_code_code
validate :check_we_have_discount_code_if_we_have_discount_code_code
def set_discount_code_from_discount_code_code
unless self.discount_code_code.blank?
self.discount_code = DiscountCode.find_by_code(self.discount_code_code)
end
end
def check_we_have_discount_code_if_we_have_discount_code_code
if !self.discount_code_code.blank? && !self.discount_code
self.errors.add(:discount_code, "is not a valid discount code")
end
end
end
Your form (which i'd expect to be a form_for @booking) should include something like this
<%= f.text_field :discount_code_code %>
which will come through in params like
params = {:booking => {:discount_code_code => "12dafj1213"}}
and then in the controller you should just say
@booking = Booking.new(params[:booking])
if @booking.save
...etc
Upvotes: 4