Errors in model namespaces - ruby-on-rails

I broke up my signup into an overall Signup model with multiple model namespaces (I believe these are what they are called) into separate files. For example,
Signup.rb
class ContractorSignup < ActiveRecord::Base
# It has fields of first_name, last_name, email, phone_number, address
end
In the signup folder there are these models
ContractorSignup::Personal < Signup
validates_presence_of :first_name, :last_name, :email, :phone_number
end
In the form I am using the main model
= form_for #contractor_signup, url: signup_step_path('email') do |form|
= form.label :first_name
= form.text_field :first_name
= form.submit "Next"
The form comes back responding to the correct validation but I cannot figure out how to grab the errors that it captures based on the validation.
This next is for a Rails wizard built duplicating this person's talk. http://www.codepainter.ca/2013/10/ultra-light-maintainable-wizards-in.html
If I do a #contractor_signup.errors.inspect I see no messages in #contractor_signup.errors.inspect when I am filling in a completely blank form. However, I found that if I submit a form with everything but first name, or last name filled out I receive a message in errors saying first_name []

Related

Validating a Rails form field that has to run through another model before saving

I have a Ruby on Rails (Ruby 2.5.1, Rails 5.1) application which deals with flights; among other things, it has a Flight model and an Airline model, with Flight belongs_to :airline and Airline has_many :flights. Airline has an iata_code column which contains the two-letter IATA airline code (i.e. AA, UA, WN, F9).
For the flight entry form, I want the user to be able to enter an arbitrary IATA code, rather than selecting an airline from a dropdown. If the IATA code the user enters matches a record in the Airline table, then the Flight.airline_id column should be set to that airline's ID. If the IATA code doesn't match an airline in my database, then the airline should be created using the IATA code provided, and that new airline's ID should be assigned to Flight.airline_id.
I currently have this working by having an Airline IATA code field in my add/edit flight form (note that the form field is named :airline_iata instead of :airline_id):
<%= f.label :airline_iata, "Airline code" %>
<%= f.text_field :airline_iata, class: "form-control code airline-iata", maxlength: 2, placeholder: 'AA' %>
Then, in my Flights controller's create and update action, I try to look up the airline before I save the flight, and set the airline_id parameter (create is below, but update is similar):
def create
params[:flight][:airline_id] = Airline.find_or_create_by!(:iata_code => params[:flight][:airline_iata].upcase).id
#flight = current_traveler.flights.build(flight_params)
if #flight.save
redirect_to event_path(current_traveler.event)
else
render "new"
end
end
This approach is working for me, except that I am unable to figure out how to do validation on the Airline IATA code field from the flight form. The Airline model validates the code (presence: true, length: { is: 2 }, uniqueness: { case_sensitive: false }), so if the user inputs an invalid IATA code, the Airline creation will fail, and thus the Flight creation will fail. However, I won't get the usual validation errors on the Flight form (e.g. error message, form fields with errors highlighted) since Flight's problem is that the airline_id (which isn't directly on the Flight form) isn't present, rather than that airline_iata in the Flight form is invalid.
How can I set it up so that this form field that has to interact with the Airport model before submission can run the Airport model's validation on a Flight form field, and return form validation errors accordingly?
You can try to use nested form attributes and add before_validation hook which will override the association:
<%= f.fields_for :airline do |airline_form| %>
<%= airline_form.label :iata_code, "Airline code" %>
<%= airline_form.text_field :iata_code %>
<% end %>
In flight.rb you should have
accept_nested_attributes_for :airline
before_validation :check_existing_airline, on: :create
def check_existing_airline
if airline.new_record? && existing_airline = Airline.find_by(iata_code: airline.iata_code)
self.airline = exisitng_airline
end
end

Do form validation that does not use database

I have a form and I have made some inputs required. After submitting the form that value will be sent to an API. I know that the validations are put into model file but since I do not have a database, how can I use the rails validation?
Right now I am validating the code inside a controller using if else.
if !params[:groups][:name].blank? && !params[:groups][:make].blank? && !params[:groups][:model].blank? && !params[:groups][:firmware].blank?
This does the work but it is not very elegant.
Take a look at ActiveModel, it lets you do "model things" without the database. There were some limitations that made me not use it in the end (I think related to associations) but for simple stuff it's great (and it's a part of how ActiveRecord works.
Example code from docs
class Person
include ActiveModel::Model
attr_accessor :name, :age
validates :name, :age, presence: true
end
this is easy. On the form input fields that you NEED, add required: true For example:
<%= form.for #something do |f| %>
<%= f.text_field :title, placeholder: 'Title', required: true %>
<% end %>
The user gets an error if the required fields are not filled out correctlty.
Is this what you mean?
Justin
EDIT
I guess I would look at using the gem
client_side_validations
Let us know how you go

ActiveAdmin set up for resource, but won't create new item through custom form

I have ActiveAdmin setup in my rails application version 3.2 where I have a BlogPost model set up perfectly fine so I can view index without an issue.
But when I create a new blogpost like
ActiveAdmin.register BlogPost do
index do
column :title do |post|
link_to post.title, blog_post_path(post)
end
column :body
column :created_at
column :image_url
default_actions
end
form do |f|
f.inputs "Blog Post" do
f.input :title
f.input :body, as: :html_editor
f.input :image_url
end
f.actions
end
end
It does nothing and doesn't actually create a new post, nor throw an error. It just refreshes the page. I'm also using default resources, so that my blog_post_controller inherits from ApplicationController instead of InheritedResources.
What could be the cause of the issue, or what more do I need to configure for activeadmin to hit the create route through post on my blog_post_controller?
Turns out I was validating for another field that I wasn't sending in the post request, and subsequently was failing silently.
I just encountered this same issue and the problem was that I was validating presence of a foreign key on child associations...but the parent object hadn't yet been created so there was no ID present to validate.
Solved this problem by adding :inverse_of => :parent_model_name to the association on the parent model and updating validation on the child models to validates :parent_model_name, :presence => true instead of validates :parent_object_id
Here's a good resource - https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through

Rails 4: How to display fields with error in red?

First question: how to validate a model relation and mark it in form when validation failed.
I have a subject model:
class Subject < ActiveRecord::Base
belongs_to :semester
validates_presence_of :semester
end
In my view (form):
<%= select_tag :semester, options_from_collection_for_select(#semesters,"id","name") %>
The validates_presence_of works fine. But when the validation fails (user forgot to enter semester ). The semester input is not marked in red.
Second question: how to validate an input field.
In my view, I also have a university input field, but model subject has no relationship with university, no field university in subject table. So how to validate it and mark it in red.
Thanks in advance.
If you want to get the fields with error displayed in red "out of the box", you must use a form builder. The code will looks like f.select ... instead of using select_tag.
With the form builder, the fields with errors are created inside a <div class="field_with_errors">...</div>. The css file generated by scaffolding displays these fields in red; if you're not using it, you must add the css rules to your css.
# app/models/subject.rb
class Subject < ActiveRecord::Base
belongs_to :semester
validates :semester, :university, presence: true # new syntax http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates
end
# app/views/subjects/_form.html.erb
<%= form_for #subject do |f| %>
Semestr: <%= f.collection_select :semester_id, Semestr.all, :id, :name, prompt: true %>
University: <%= f.text_field :univercity %>
<% end %>
For more information about building forms in rails (with validations enabled) you could find there http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html
Those "red errors" that you hope for are probably coming from a form helper gem like formtastic, feel free to check that out.
I have literally no idea what your second question is asking, but if you're looking for a custom validation. Check out the rails docs on them for help.
If you'd like more help, (please) edit your question to be more clear (thanks)

Validate field is unique compared to another field in same form

Say I have two fields in a new or edit form:
<%= f.text_field :email %>
<%= f.text_field :parent_email %>
How, in my model, can I validate that parent_email is different from email? The exclusion option seems like it might work, but I can't figure out how to access the email field's value within the model. Do I need to implement this in the controller instead?
validates :parent_email, exclusion: self.email # doesn't work, nor does :email
The following should work (but I guess there are cooler solutions out there):
class User
validate :email_differs_from_parent_email
private
def email_differs_from_parent_email
if email == parent_email
errors.add(:parent_email, "parent_email must differ from email")
end
end
end

Resources