How to use collection_select in rails 4 from a model module? - ruby-on-rails

I am trying to use collection_select tag for the default _form.html.erb using a concern/module, I need to set a hash including some department names.
Here is my app/models/concerns/SetDepartment.rb
module Set_Department
extend ActiveSupport :: Concern
def department
department {
1=>"Amatitlán",
2=>"Chinautla",
3=>"Chuarrancho"
}
end
end
Here is the model where I want to call the department method:
class Aplicante < ActiveRecord::Base
include SetDepartment
validates :titulo_id, :primer_nombre,
:primer_apellido, :dpi, :direccion_linea_1,:zona, :department_id, :username,
presence: true
validates :dpi,:username, uniqueness: true
has_secure_password
end
Now, I need to include this hash in a collection_select tag on my app/views/applicants/_form.html.erb
#...
<div class="field">
<%= f.label :department_id %><br>
<%= f.collection_select :department_id, Aplicante.department, Aplicante.department %>
</div>
#...
Obviously, this does not work but I can not think on anything else.
I have searched through the internet but I just get tough explinations and none of them involves a module... is it even possible?

Solved!
I was using the wrong method..
We can not use a collection_select helper with a hash, instead, we need to use the regular select method.
Collection_select is used when you have two models and you want to combine their different values in a drop down menu.
Information about how to use the select tag with a hash here:
http://apidock.com/rails/ActionView/Helpers/FormTagHelper/select_tag

Related

Custom display label for grouped_collection_select

I have the following grouped_collection_select in my View:
<%= grouped_collection_select(:classroom, :course_id, #classrooms, :courses, :name, :id, :name) %>
How do I customize the display label such that it is the concatenation of 2 attributes?
grouped_collection_select takes a method-name as the parameter for the label. Labels are generated by calling that method on each object in the collection.
In your example, the method is called :name but you could create a method on your Classroom class that contains the two attributes you want eg:
# totally made up - use whatever attributes and method-name you want
def name_and_location
[name, location].join(': ')
end
then just use it in the collection-select:
<%= grouped_collection_select(:classroom, :course_id, #classrooms, :courses, :name_and_location, :id, :name) %>
Note: the above example is for the group-label... hut you can equally well do the same for the individual item-label, just use the last parameter and put the method on your Course model instead.

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

How to default collection_check_boxes to checked?

I have this line that I'm trying to default to checked <%= f.collection_check_boxes :committed, checked, Date::ABBR_DAYNAMES, :downcase, :to_s, %>
In db t.text "committed".
I tried variations of checked & true, but maybe I overlooked something.
Here's the Gist of it.
Here is a quick answer on how to add checked as the default to the collection_check_boxes form helper since it took me some time to figure it out. Break it into a block and you can set checked and add classes. More info at http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_check_boxes.
<%= f.collection_check_boxes(:author_ids, Author.all, :id, :name) do |b| %>
<%= b.label(class: "check_box") { b.check_box(checked: true, class: "add_margin") + b.text } %>
<% end %>
You are using a form_for, so that f is a form builder. This means that it is bound to the object you initialized it with, let's call it #habit. Since you're calling collection_check_boxes on the form builder, it will do something like #habit.send(:commit) to consult whether or not it should have the check box checked, and currently (apparently) it is not. In other words, if you want to use form_for you need to have this "everything is checked" fact represented in the model itself.
Now I am not sure what your model layer looks like, so I'll address a few scenarios. If you have a has_and_belongs_to_many relationship like this:
class Habit < ActiveRecord::Base
has_and_belongs_to_many :committed_days
end
class CommittedDay < ActiveRecord::Base
has_and_belongs_to_many :habits
# let's assume it has the columns :id and :name
# also, let's assume the n:m table committed_days_habits exists
end
Then I think the easiest way is in the controller itself do something like this:
def new
#habit = Habit.new
#habit.committed_day_ids = CommittedDay.all.map(&:id)
end
And in your ERB do:
<%= f.collection_check_boxes(:committed_day_ids, CommittedDay.all, :id, :name)
Now, it might be an overkill to do this with a has-and-belongs-to-many, especially with days of week (it means the CommittedDay table has 7 records, one for each day, which is kinda awkward). So you could also consider simply serializing an array of days of week into the db, and then just make sure the default for that column contains all of them.
The ERB will be similar to what you wrote:
<%= f.collection_check_boxes :committed, Date::ABBR_DAYNAMES, :downcase, :to_s %>
If you're using Postgres your class can be simply:
class Habit < ActiveRecord::Base
end
And the serialization code would be in the migration:
# downcase is used since in the ERB you are using :downcase for the id method
t.text :committed, default: Date::ABBR_DAYNAMES.map(&:downcase), array: true
If you are not using Postgres, you can use Rails serialization which is DB agnostic:
class Habit < ActiveRecord::Base
serialize :committed, Array
end
And then your migration would look like this:
t.text :committed, default: Date::ABBR_DAYNAMES.map(&:downcase).to_yaml

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)

Validating field's presence fails even though the field is not blank

I'm trying to fill out an array with values from checkboxes. It works just fine when creating a record, but fails validation when editing. The params look right, which is what really confuses me:
"record"=>{... "type_array"=>["accounting"], ...}
It looks the same as the params from creating a new record. The fields in New.html.erb and Edit.html.erb also use the same markup.
Edit.html.erb
<div class="field">
<%= f.label :type_array, "What type of record?" %><br />
<% ["accounting", "agriculture", "automotive"].each do |type| %>
<%= check_box_tag 'record[type_array][]', type, (true if #record.type_list.include? type),
:id => type %>
<%= label_tag type, type.titleize, :class => type %><br />
<% end %>
</div>
Parts of Record.rb
validates :type_array, :presence => true
attr_accessor :type_array
attr_accessible :type_array
before_validation :set_type_list
private
def set_type_list
self.type_list = type_array.join ',' if type_array.present?
end
Am I missing something? When I remove the type_array validation and fill out the form, it acts like type_array is empty. Somewhere along the line, it must be lost or something.
I appreciate any help.
(Sidenote: if anyone has a better way to do the list of checkboxes, let me know)
Delete the line attr_accessor :type_array.
This creates accessor methods to a new instance variable, not to the model attribute type_array, which means that #record.type_array now refers to that instance variable instead of the attribute.
You almost never use attr_accessor or it's siblings attr_reader and attr_writer in Rails because you want to deal with model attributes, not instance variables.
Edit: You're using type_array as a virtual attribute.
class Record < ActiveRecord::Base
validates :type_array, :presence => true
attr_accessible :type_array
def type_array=(val)
self.type_list = val.join ','
end
def type_array
self.type_list.split ','
end
def type_array_before_type_cast
type_array
end
end
For the reason why you need that last function definition, see this question.

Resources