Simple_form with Form Object missing Mapping - ruby-on-rails

I am using simple_form_for
<%= simple_form_for( #form_object, url: wizard_path, :method => :put) do |f| %>
<%= f.input :website %>
<%= f.submit %>
</div>
<% end %>
However, I am also using a Form Object
class Base
include ActiveModel::Model
# Validations
# Delegations
# Initializer
end
My issue is that my inputs are not mapping to my database columns, so https://github.com/plataformatec/simple_form#available-input-types-and-defaults-for-each-column-type
None of these show up ,and can I create custom mappings.
How can I allow Simple_form to see my column types and work correctly?
If I check the class of my delegated fields, they seem to show as :string or :integer, etc.

simple_form uses 2 methods to determine the input type field mapping from a standard model (type_for_attribute and has_attribute?). Source
Since you are wrapping the model in another layer but still want the inference that simple_form provides you just need to delegate these calls to the original model via
class Wrapper
include ActiveModel::Model
attr_reader :model
delegate :type_for_attribute, :has_attribute?, to: :model
def initialize(model)
#model = model
end
end
However if you were not wrapping the model you would need to define these methods yourself such as (using the new rails 5.2 Attribute API)
class NonWrapper
include ActiveModel::Model
include ActiveModel::Attributes
attribute :name, :string
def type_for_attribute(name)
self.class.attribute_types[name]
end
def has_attribute?(name)
attributes.key?(name.to_s)
end
end
Example
a = NonWrapper.new(name: 'engineersmnky')
a.has_attribute?(:name)
#=> true
a.type_for_attribute(:name)
#=> => #<ActiveModel::Type::Value:0x00007fffcdeda790 #precision=nil, #scale=nil, #limit=nil>
Note other additions may be required for a form object like this to work with simple_form. This answer simply explains how to handle the input mapping inference

Related

undefined method for text_field in ruby on rails

<%= f.text_field :quantity_available, :readonly => "readonly",:class=>"mg-text-field" %>
error:
undefined method `quantity_available' for #<:0xaf32b824>
In the new form I have shown "quantity_available" whose value I am getting through jquery and this field is only for displaying purpose so this has not been saved in model but I want to do same in edit form in which I am getting error as
how to resolve this?
You can define the field in the Model without it needing to be a persisted column in the table.
class Model < ActiveRecord::Base
attr_accessor :quantity_available
# other stuff here
end
For that purpose you can use text_field_tag. For more check on http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html
<%= text_field_tag 'quantity_available',nil, class: "mg-text-field", readonly: true %>

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

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

Rails 4 - Convert datetime into separate date and time fields

How can you convert a mysql datetime field into two form fields (1) date only, (2) time only, and combine both fields back into datetime format on form submit?
This would allow the use of the following gems, but store the dates in a single datetime field:
gem 'bootstrap-datepicker-rails'
gem 'bootstrap-timepicker-rails'
Thanks in advance!
Found the solution with help from #Althaf
Added virtual attributes to model.rb
Used before_save callback to convert back to datetime.
before_save :convert_to_datetime
def sched_date_field
sched_date.strftime("%d/%m/%Y") if sched_date.present?
end
def sched_time_field
sched_time.strftime("%I:%M%p") if sched_time.present?
end
def sched_date_field=(date)
# Change back to datetime friendly format
#sched_date_field = Date.parse(date).strftime("%Y-%m-%d")
end
def sched_time_field=(time)
# Change back to datetime friendly format
#sched_time_field = Time.parse(time).strftime("%H:%M:%S")
end
def convert_to_datetime
self.sched_time = DateTime.parse("#{#sched_date_field} #{#sched_time_field}")
end
Using Rails 4, needed to add sched_date_field and sched_time_field to strong params in controller.rb
Here are the fields in _form.html.erb
<%= f.label :sched_date_field, "Scheduled Date" %>
<%= f.text_field :sched_date_field, :class => "datepicker" %>
<%= f.label :sched_time_field, "Scheduled Time" %>
<%= f.text_field :sched_time_field, :class => "timepicker" %>
You can use date_time_attribute gem:
class MyModel < ActiveRecord::Base
include DateTimeAttribute
date_time_attribute :scheduled_at
end
It will allow you to set schedule_at_date and scheduled_at_time separately. Once attributes are set, values will be combined into schedule_at.
You could use virtual attributes See this Railscast and if you have a pro subscription the revised one.
Basically in the view you would the following
<%= f.label :date_field %>
<%= f.text :date_field %>
<%= f.label :time_field %>
<%= f.text :time_field %>
Your database would still keep a field which I'll call full_date
Now in your model you would have to define the above 2 fields as follows.
def date_field # What this returns will be what is shown in the field
full_date.strftime("%m-%d'%y") if full_date.present?
end
def time_field
full_date.strftime("%I:%M%p") if full_date.present?
end
def time_field=(time)
full_date = DateTime.parse("#{date_field} #{time_field})
end
Since it looks like you are using Rails 4, you'll have to permit date_field and time_field in your strong parameters.
Alternatively, I set up a solution in the controller that does all the datetime conversions before the object gets created, because changing the data in the model impacted all my tests and validations. "Event" is the object I'm creating here with the datetime values being assigned to it.
#In the controller:
def convert_to_datetime_and_assign(event, params)
date_field = Date.parse(params[:date_field]).strftime("%Y-%m-%d")
start_time_field = Time.parse(params[:start_time_field]).strftime("%H:%M:%S")
end_time_field = Time.parse(params[:end_time_field]).strftime("%H:%M:%S")
event.start_time = DateTime.parse("#{date_field} #{start_time_field}")
event.end_time = DateTime.parse("#{date_field} #{end_time_field}")
event
rescue ArgumentError
event.errors.add(:start_time, :invalid, message: "Date or time was invalid")
event
end
in the create and update controller methods I called the method above:
#event = convert_to_datetime_and_assign(#event, event_params)
I added fields for date_field, start_time_field and end_time_field in my forms for creating/updating "events". And in the model I added an accessor to be able to access those values.
attr_accessor :date_field, :start_time_field, :end_time_field

Customize Formtastic to automatically add the class "required" to elements that are required

How would I go about having Formtastic automatically add the class "required" to elements that are required by rails validation?
I see that you can create custom inputs by adding the specified inputs in app/inputs but I don't see a way to check to see if it's required.
I'm assuming it would be something like:
class StringInput < Formtastic::Inputs::StringInput
include Base::Stringish
include Base::Validations
def input_html_options
if required?
super.merge(:class => "required")
end
end
end
but it's not working :|
I'm sure it does this anyway if you just ask it to:
<%= form.input :tutor_id, as: :select, collection: #student.tutors.all(order: 'name'), required: true %>
(this is Ruby 1.9 syntax)

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