Ruby on Rails- Making input required for a form - ruby-on-rails

I am trying to make this input in my search required to start a search. I tried :validate if there is input but that didn't work. Any suggestions?
<%= text_field_tag "location", params[:location], :placeholder => 'City, zipcode, or address' %>

change the syntax
<%= text_field_tag "location", "#{params[:location]}", :placeholder => 'City, zipcode, or address' {:required => true} %>
and add this to your model
validates :location, presence: true

In whatever model the location belongs to, try adding this syntax:
class whatever < ActiveRecord::Base
validates :location, presence: true
end
make sure that location is part of attar_accessible in your model.

Related

Couldn't find Manufacturer with 'id'= (blank)

I am trying to create a web application to practise my Ruby on Rails skill. I have a few entities in my database manufacturers, models, tints, prices
manufacturers {id, name} - stores the make of the car
models {id, manufacturer_id, name} - stores the models of the car
tints {id, manufacturer_id, model_id, front, sides, rear} - stores the length of tint required
prices {id, description, price } - stores the price of the item
I created a page to generate a quotation for window tinting. The page includes drop-down menus to let user to select manufacturer, model, type of film(front), type of film(side+rear)
Below is the code for the form
<%= form_tag('/quotation/tints/generate') do %>
<%= label :manufacturer_id, 'Manufacturer' %>
<div class="field">
<%= collection_select(:tint, :manufacturer_id, Manufacturer.order(:name), :id, :name, {:prompt => "Select Manufacturer"}) %>
</div>
Model:
<div class="field">
<%= grouped_collection_select(:tint, :model_id, Manufacturer.order(:name), :models, :name, :id, :name, {:prompt => "Select Model"}) %>
</div>
<%= label :price_front, 'Front Tint' %>
<div class="field">
<%= collection_select(:price, :price_front, Price.order(:name), :id, :name, {:prompt => "Select Front Tint"}) %>
</div>
<%= label :price_rear, 'Size and Back Tint' %>
<div class="field">
<%= collection_select(:price, :price_rear, Price.order(:name), :id, :name, {:prompt => "Select Side & Rear Tint"}) %>
</div>
<div class="form-group">
<%= submit_tag 'Submit' %>
</div>
<% end %>
When the form is submitted, it should be redirected to /quotation/tints/generate and display the value from the dropdown menu. However, I received an error, saying that Couldn't find Manufacturer with 'id'=. The code that caused the error is shown below
def generate
#manufacturers = Manufacturer.find(params[:manufacturer_id])
end
Here is the parameter from the debug log
{"utf8"=>"✓",
"authenticity_token"=>"Pl2bXiRT0AoF4i0h1RCHDbuvaKJNZOkV5ULQHKxDQgZzBWWLJ2mH7ddb9akwgxbloxBIHoVaT3pcwoIGcRufpg==",
"tint"=>{"manufacturer_id"=>"7", "model_id"=>"6"},
"price"=>{"price_front"=>"1", "price_rear"=>"2"},
"commit"=>"Submit"}
I can see that the id of each drop down value are shown up correctly in the parameter list. However, I coundn't able to print the value at /quotation/tints/generate nor get the name of the manufacturer or model.
Here is routes.rb:
get '/quotation/tints' => 'tints#quotation', :as => 'tints_quotation'
post '/quotation/tints/generate' => 'tints#generate', :as => 'generate_tints_quotation'
Tint.rb:
class Tint < ApplicationRecord
has_many :manufacturers
has_many :models
belongs_to :manufacturer
belongs_to :model
validates_uniqueness_of :model_id, :scope => [:manufacturer_id]
end
Model.rb:
class Model < ApplicationRecord
belongs_to :manufacturer, :dependent => :destroy
validates :name, :presence => true
validates_uniqueness_of :name, :scope => [:manufacturer_id]
before_save :capitalize_content
end
Manufacruter.rb:
class Manufacturer < ApplicationRecord
has_many :models, :dependent => :destroy
validates :name, :presence => true, uniqueness: { case_sensitive: false }
before_save :capitalize_content
end
tints.controller.rb:
def quotation
render 'quotation'
end
def generate
#manufacturers = Manufacturer.find(params[:manufacturer_id])
end
generate.html.erb:
<%= #manufacturers.name %>
I'm trying to print the manufacturer selected
I have tried multiple ways to define it, but I am still facing the same error. Any help is greatly appreciated.
In your params, manufacturer_id is a nested value of tint, as opposed to being a direct key of the params hash. Try the following:
def generate
#manufacturers = Manufacturer.find(params[:tint][:manufacturer_id])
end

Serializing to array shows empty brackets and formats incorrectly in Rails

I have a department field in my org model where i want to store the list of department as an array. I have this in my model:
class Org < ActiveRecord::Base
serialize :department, Array
attr_accessible :name, :department
before_validation :update_department
validates :name, presence: true
def update_department
if department_changed? and department.is_a?(String)
self.department = self.department.split(',').collect(&:strip)
end
end
end
and the view:
<%= f.text_area :department, :cols => "10", :rows => "10" %>
now Whenever i try to sign up, the department field has [] present and when i try to update, the department is already ["[department1", "department2]"].
I want [] to be removed while signing up and department1, department2 to show up when updating. Also the array is saved incorrectly it should be ["department1", "department2"].
Please Help.
You Should join the array by comma
object.join(',')
in your example:
<%= f.text_area :department,value: #org.department.join(','), :cols => "10", :rows => "10" %>

Handling model requirements within the same view?

First and foremost, thanks for taking time to read and respond to my questions. I really appreciate it.
I'm not looking for the exact code on how to achieve the following but more of a direction or path I should follow.
Users that are logged in can create different courses. I've added a requirement (a provider) for each course and I want the user to have at least one provider associated (using rolify for this) to them before doing so but I'd like this to be on the same view (courses#new)
I've tried the following:
Nested forms (Doesn't work since I require at least one provider upon course creation)
Adding the providers#new in a modal on the page (can't call a controller from another one using form_form(#provier)
I've thought of the following:
Redirect the users to providers#new if they haven't created one first
Add a modal with a form_tag element that creates a provider and then refreshes the underlying page.
What are your thoughts? Better ideas?
Thanks!
Francis
My courses#new (_form) view
<%= simple_form_for(#course) do |f| %>
<%= f.error_notification %>
<%= f.input :name %>
<%= f.input :description, as: :text, input_html: { rows: '2' } %>
<%= f.association :provider, :value_method => :id, collection: Provider.with_role(:provider_admin, current_user), input_html: { class: 'input-large' }, include_blank: false %>
<div class="form-actions">
<%= f.button :submit, :class => 'btn-primary' %>
<%= link_to "Cancel", :back, class: 'btn' %>
</div>
<% end %>
models/provider.rb
class Provider < ActiveRecord::Base
attr_accessible :description, :name
validates :name, :presence => true
validates :description, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :length => { :minimum => 6, :maximum => 100 }
has_many :courses
end
models/course.rb
class Course < ActiveRecord::Base
attr_accessible :description, :name, :provider_id
validates :name, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :presence => true
validates :description, :length => { :minimum => 6, :maximum => 256 }
validates :provider_id, :presence => true
belongs_to :provider
has_many :sessions, :dependent => :destroy
end
I like the idea where you do a redirect in courses#new to providers#new when !current_user.provider.any?.
But I would probably go the nested forms way. You can use one form to create a new course and a new provider if a user doesn't have a provider. Have a look at http://railscasts.com/episodes/196-nested-model-form-revised to get a quick idea. I think that this would be best UI wise.

Ruby on Rails: How to validate nested attributes on certain condition?

I have these models:
class Organisation < ActiveRecord::Base
has_many :people
has_one :address, :as => :addressable,
:dependent => :destroy
accepts_nested_attributes_for :address, :allow_destroy => true
end
class Person < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :organisation_id, :address_attributes
belongs_to :user
belongs_to :organisation
has_one :address, :as => :addressable,
:dependent => :destroy
accepts_nested_attributes_for :address, :allow_destroy => true
# These two methods seem to have no effect at all!
validates_presence_of :organisation, :unless => "address.present?"
validates_associated :address, :unless => "organisation.present?"
end
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
validates_presence_of :line1, :line2, :city, :zip
end
...and these views:
_fields.html.erb:
<%= render 'shared/error_messages', :object => f.object %>
<fieldset>
<div class="left">
<%= f.label :first_name %><br/>
<%= f.text_field :first_name %>
</div>
<div>
<%= f.label :last_name %><br/>
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :email %><br/>
<%= f.text_field :email %>
</div>
<div>
<%= f.label :organisation_id %><br/>
<%= f.select(:organisation_id, current_user.organisation_names, {:include_blank => "--- None ---"}, :id => 'organisation_select') %>
</div>
</fieldset>
<%= f.fields_for :address do |address| %>
<%= render 'shared/address', :f => address %>
<% end %>
_address.html.erb:
<fieldset id="address_fields">
<div>
<%= f.label :line1 %>
<%= f.text_field :line1 %>
</div>
<div>
<%= f.label :line2 %>
<%= f.text_field :line2 %>
</div>
<div>
<%= f.label :zip %>
<%= f.text_field :zip %>
</div>
<div>
<%= f.label :city %>
<%= f.text_field :city %>
</div>
</fieldset>
people_controller.rb:
def new
puts params.inspect
#person = Person.new(:organisation_id => params[:organisation_id])
#person.build_address
#title = "New person"
end
{"action"=>"new", "controller"=>"people"}
def edit
puts params.inspect
#title = #person.name
end
{"action"=>"edit", "id"=>"69", "controller"=>"people"}
def create
puts params.inspect
if params[:organisation_id]
#person = current_user.organisations.build_person(params[:person])
else
#person = current_user.people.build(params[:person])
end
if #person.save
flash[:success] = "Person created."
redirect_to people_path
else
render :action => "new"
end
end
{"commit"=>"Create", "action"=>"create", "person"=>{"last_name"=>"Doe", "organisation_id"=>"9", "email"=>"john.doe#email.com", "first_name"=>"John", "address_attributes"=>{"city"=>"Chicago", "zip"=>"12345", "line2"=>"Apt 1", "line1"=>"1 Main Street"}}, "authenticity_token"=>"Jp3XVLbA3X1SOigPezYFfEol0FGjcMHRTy6jQeM1OuI=", "controller"=>"people", "utf8"=>"✓"}
Inside my Person model I need to make sure that only if a person's organisation_id is blank, that person's address fields have to be present.
I tried something like this:
validates :address, :presence => true, :if => "organisation_id.blank?"
But it's not working.
How can this be done?
Thanks for any help.
First of all, I want to be sure that you mean blank? rather than present?. Typically, I see this:
validate :address, :presence_of => true, :if => 'organisation.present?'
Meaning, you only want to validate address if organisation is also present.
Regarding, :accepts_nested_attributes_for, are you using this feature by passing in nested form attributes, or some such thing? I just want to make sure you absolutely need to use this functionality. If you are not actually dealing with nested form attributes, you can implement cascading validation using:
validates_associated :address
If you do need to use :accepts_nested_attributes, be sure to check out the :reject_if parameter. Basically, you can reject adding an attribute (and it's descendants) altogether if certain conditions apply:
accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => :no_organisation
def no_organisation(attributes)
attributes[:organisation_id].blank?
end
Now, if none of the above apply, let's take a look at your syntax:
It should work, :if/:unless take symbols, strings and procs. You don't need to point to the foreign_key, but can simplify by pointing to:
:if => "organisation.blank?"
You have other validations in the Address model, correct? Is Address being validated when you don't want it to? Or is Address not being validated? I can help you test it out in the console if you can give me some additional details.
To make things easier for myself re: mass-assignment, I changed the rails config: config.active_record.whitelist_attributes = false
I created a gist for you to follow along
I have a sample project as well. Let me know if you are interested.
Basic points:
Added the following to Person to ensure that either Org or Address are valid:
validates_presence_of :organisation, :unless => "address.present?"
validates_associated :address, :unless => "organisation.present?"
Added validation to Address to trigger errors when Org is not present:
validates_presence_of :line1, :line2, :city, :zip
I was able to produce the requirements you are seeking. Please look at the gist I created where I have a full console test plan.
I added a controller file to the previous gist.
Overview:
All you should need to create the person is:
#person = current_user.people.build(params[:person])
:organisation_id will always be found off of the :person param node, like so:
params[:person][:organisation_id]
So you're if will never be true.
I updated the gist with the necessary changes to the controller, the model and the form.
Overview:
You need to cleanup your controller. You are using accepts_nested_attribute, so in the :create, you only care about params[:person]. Additionally, in the render :new, you need to setup any instance variables that the partial will use. This does NOT go back through the :new action. The :new and :edit actions also need to be simplified.
Your Person model needs to use the :reject_if argument because the Address fields are coming back to the :create action as :address_attributes => {:line1 => '', :line2 => '', etc}. you only want to create the association if any have values. Then your validates_presence_of for :organisation will work just fine.
Your form needs to pass the organisation id to the controller, rather than the organisation names
It's all in the gist
Should be the final gist.
Overview:
Add the following to your edit action right after building the #person:
#person.build_address if #person.address.nil?
This ensure that you have the address inputs, even if the #person.address does not exist. It doesn't exist, because of the :reject_if condition on accepts_nested_attributes
I DRYed up the :reject_if as follows. It's a little hacky, but has some utility:
accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => :attributes_blank?
def attributes_blank?(attrs)
attrs.except('id').values.all?(&:blank?)
end
a. attrs -> the result of params[:person][:address]
b. .except('id') -> return all key-values except for 'id'
c. .values -> return all values from a hash as an array
d. .all? -> do all elements in the array satisfy the following check
e. &:blank -> ruby shorthand for a block, like this: all?{ |v| v.blank? }
Are you sure you didn't mean:
validates :address, :presence => true, :if => organisation_id.nil?
A more simple approach might be to add a custom validator. It's super easy, and you don't have to stumble on syntax or try to figure out why Rails' magic isn't working.
Inside my Person model I need to make sure that only if a person's organisation_id is blank, that person's address fields have to be present.
class Person < ActiveRecord::Base
...
validate :address_if_organisation_id_is_present
private
def address_if_organisation_id_is_present
return true unless organisation_id
errors.add(:address, "cannot be blank") unless address
end
end
Adding to a model's errors will prevent it from saving. Note: you may wish to use address.blank? or address.empty? as discussed in other answers, but you can define this for the behavior you'd like.

Make a fields_for block conditional

I have a User Model and an Instructor Model. There is a one-to-one relationship between user and instructor. And some users will be instructors and some will not. As such I have a registration form that uses a fields_for method to write to both.
How can I write to the instructor table only on the condition that they say they are an instructor, such as through a checkbox. And when they do write I want to maintain my validations of the table along with the rest of the form
Ideally this would work best if I can do this through the model, but I'm open to all suggestions.
Instructor Model
class Instructor < ActiveRecord::Base
belongs_to :user
validates_presence_of :school_url, :etc...
attr_accessible :school_url, :etc...
end
User Model
class User < ActiveRecord::Base
has_one :instructor, :dependent => :destroy
validates_uniqueness_of :email
validates :email, :confirmation => true
accepts_nested_attributes_for :instructor
attr_accessible :email, :password, :instructor_attributes, :etc
end
Form in HAML
- resource.build_instructor
- form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
= hidden_field_tag :destination, { :value => destination}
.field
= f.label :firstname, "First Name"
= f.text_field :firstname
.field
= f.label :lastname, "Last Name"
= f.text_field :lastname
.field
= f.label :email, "E-Mail"
= f.email_field :email
.field
= f.label :email_confirmation, "Confirm E-Mail"
= f.email_field :email_confirmation
.field
= f.label :password
= f.password_field :password
.field
= f.label :password_confirmation, "Confirm Password"
= f.password_field :password_confirmation
#instructor-box
%p
%span.bold Are you an instructor?
= check_box_tag :instructor_check
%span Yes, I am an instructor
= f.fields_for :instructor do |i|
= render "/users/registrations/instructor", :form => i
I fixed the problem. It seems all too obvious now. In order for the fields_for to be cancelled out all I have to do is delete the instructor_attributes that are being created by the form in the controller. For example:
Create
# params[:user] => {:email => "justin#example.edu", ..., :instructor_attributes => { :school_url => "www.example.edu", ...}
# params[:instructor_check] => "0"
Given these parameters being passed, I can easily delete the attributes that are to be saved and the rails no longer tries to create a new record for instructor that's to be associated with user. This is literally the code I used. Not the most elegant, but it works.
params[:user].delete :instructor_attributes if params[:instructor_check] = "0"
This recognizes that no instructor profile is being created for the user and thus does not write to the table. Before it was sending back blank attributes and failing on the validations.

Resources