I'm trying to create an event, the event has a date and a time field. When creating the table for protest I didn't add a time field, so I had to run a migration to add a time field. But I am now having issues when creating the form. What is the elegant solution to create a time and date field?
class CreateProtests < ActiveRecord::Migration[5.1]
def change
create_table :protests do |t|
t.string :name
t.text :description
t.string :location
t.datetime :starts_at
t.references :creator, index: true, foreign_key: { to_table: :users }
end
end
end
I then added a field for the time of day:
class AddStartsAtTimeOfDayToProtests < ActiveRecord::Migration[5.1]
def change
add_column :protests, :starts_at_time_of_day, :datetime
end
end
protests/new.html.erb
<div class="col-md-12">
<div class="card">
<div class="card-header"><h2>Create A Protest</h2></div>
<div class="card-block">
<%= form_for(#protest, url: protests_path, html: {multipart: true}) do |f| %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :location %>
<%= f.text_field :location, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label "Date:" %>
<%= f.text_field :starts_at, value: "02/16/13", id: "dp2"%>
</div>
<div class="form-group">
<%= f.label "Time:" %>
<%= f.time_select :starts_at, ignore_date: true, class: "form-control"%>
</div>
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, as: :file, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Create", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
The Date and Time are both captured in the single column :starts_at so you don't need another column for the time of day.
Your form should just have:
<div class="form-group">
<%= f.label "Starts At:" %>
<%= f.datetime_select :starts_at, class: "form-control"%>
</div>
Here is a link to the docs:
https://apidock.com/rails/ActionView/Helpers/FormBuilder/datetime_select
add date_field for Date and time_field for the time to have the two fields as follows.
<div class="form-group">
<%= f.label "Date:" %>
<%= f.date_field :starts_at, class: "form-control"%>
</div>
<div class="form-group">
<%= f.label "Time:" %>
<%= f.time_field :starts_at, class: "form-control"%>
</div>
Related
I have 2 models:
class Page < ApplicationRecord
enum page_type: STATIC_PAGE_TYPES, _suffix: true
has_one :seo_setting
accepts_nested_attributes_for :seo_setting, update_only: true
validates :title, :subtitle, length: { maximum: 50 }
validates :page_type, uniqueness: true
def to_param
"#{id}-#{page_type}".parameterize
end
end
and
class SeoSetting < ApplicationRecord
mount_uploader :og_image, SeoSettingsOgImageUploader
belongs_to :page
validates :seo_title, :seo_description, :og_title, :og_description, :og_image, presence: true
end
My Page objects are created from the seeds.rb file, and when I want to edit them, I get an error: Failed to save the new associated seo_setting.
In the form I have this:
<div class="card-body">
<%= form_for([:admin, #page]) do |f| %>
<%= render 'shared/admin/error-messages', object: #page %>
<div class="form-group">
<%= f.label :title, t('admin.shared.title') %>
<%= f.text_field :title, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :subtitle, t('admin.shared.subtitle') %>
<%= f.text_field :subtitle, class: 'form-control' %>
</div>
<h3>SEO Settings</h3>
<%= f.fields_for :seo_setting, f.object.seo_setting ||= f.object.build_seo_setting do |form| %>
<div class="form-group">
<%= form.label :seo_title, t('admin.shared.seo_title') %>
<%= form.text_field :seo_title, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :seo_description, t('admin.shared.seo_description') %>
<%= form.text_area :seo_description, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_title, t('admin.shared.og_title') %>
<%= form.text_field :og_title, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_description, t('admin.shared.og_description') %>
<%= form.text_area :og_description, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_image, t('admin.shared.og_image') %>
<div class="row">
<div class="col-lg-12">
<%= image_tag(form.object.og_image.url, style: 'width: 100px') if form.object.og_image? %>
</div>
</div>
<%= form.file_field :og_image %>
<%= form.hidden_field :og_image_cache %>
</div>
<% end %>
<div class="form-group">
<%= f.submit t('admin.actions.submit'), class: 'btn btn-success' %>
<%= link_to t('admin.actions.cancel'), admin_page_path(#page) , class: 'btn btn-default' %>
</div>
<% end %>
</div>
If I remove validations from my SeoSetting model, everything is working. It seems Rails doesn't like this part: f.object.build_seo_setting, because it creates a record in my database. Any ideas of how can I solve this issue? Thanks ahead.
Just had to change this line:
<%= f.fields_for :seo_setting, f.object.seo_setting ||= f.object.build_seo_setting do |form| %>
for this one:
<%= f.fields_for :seo_setting, #page.seo_setting.nil? ? #page.build_seo_setting : #page.seo_setting do |form| %>
Looks as if the problem lies here:
accepts_nested_attributes_for :seo_setting, update_only: true
in that you only allow the updating of the seo_setting on update.
Then, when you use this code:
f.object.seo_setting ||= f.object.build_seo_setting
You're falling back to a new seo_setting if the associated object is missing.
For this to work, you'll need to either remove the update_only: true, or only render the fields for the association if the seo_setting already exists.
Accepted answer, a conditional inside fields_for line, by OP, works also with polymorphic association and nested form (fields_for). Thnx Alex.
I have a problem in my form, i want to create an entry in my "members" table, each member are connected to a "year" but I keep getting mismatches on the selection of the year.
This is my form:
<div class="field">
<%= f.label :name %><br>
<%= f.text_area :name %>
</div>
<div class="field">
<%= f.label :nickname %><br>
<%= f.text_area :nickname %>
</div>
<div class="field">
<%= f.label :year %>
<%= f.select :year, options_for_select(#years.all.map{|y| [y.year,y.id]}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
And here are the models:
class Member < ApplicationRecord
belongs_to :year
mount_uploader :image, ImageUploader
end
class Year < ApplicationRecord
has_many :members, dependent: :destroy
end
When I try to submit I get the following error:
Year(#70050157849460) expected, got "1" which is an instance of String(#9412380)
Where did I go wrong?
EDIT:
Here is the code for the controller
class MembersController < ApplicationController
def home
#members = Member.all
end
def new
#member = Member.new
#years = Year.all
end
def create
#member = Member.new(member_params)
if #member.save
flash[:success] = "Member Created"
redirect_to root_path
else
render 'form'
end
end
private
def member_params
params.require(:member).permit(:name,:nick,:position,:image,:year)
end
end
<div class="field">
<%= f.label :name %><br>
<%= f.text_area :name %>
</div>
<div class="field">
<%= f.label :nickname %><br>
<%= f.text_area :nickname %>
</div>
<div class="field">
<%= f.label :year %>
<%= f.select :year_id, options_for_select(#years.all.map{|y| [y.year,y.id]}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
or
<div class="field">
<%= f.label :name %><br>
<%= f.text_area :name %>
</div>
<div class="field">
<%= f.label :nickname %><br>
<%= f.text_area :nickname %>
</div>
<div class="field">
<%= f.label :year %>
<%= f.select :year, options_for_select(#years.all.map{|y| [y.year,y]}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
This second I did not check but first will work you need to say year_id because when you did map on collection you set id as parameter that is being passed
but on form select you basically told form to expect active record object.
so please imagine a form for a car reservation, the form contains both some client information(name, age, city..) and also the reservation informations(start_date, end_date...).
So obviously, i need to create in the same form a client first, based on the informations and then the reservation which is related to the created client:
class Client < ActiveRecord::Base
has_many :reservations
end
.
class Reservation < ActiveRecord::Base
belongs_to :client
belongs_to :voiture
end
Here is what i did until now(bad way).
The reservation informations start with f.text_field, and the client informations only with text_field(very bad way yes :( )
<%= form_for([#voiture, #voiture.reservations.new]) do |f| %>
<div class="row">
<div class="col-md-12 price_tag">
<span><%= #voiture.price %>Dhs</span>
<span class="pull-right">Par jour</span>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>Nom</label>
<%= text_field :nom, readonly: 'true', placeholder: 'Nom', class: 'form-control' %>
</div>
<div class="col-md-6">
<label>Prenom</label>
<%= text_field :prenom, readonly: 'true', placeholder: 'Prenom', class: 'form-control', disabled: 'true' %>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>CIN</label>
<%= text_field :cin, readonly: 'true', placeholder: 'CIN', class: 'form-control' %>
</div>
<div class="col-md-6">
<label>Age</label>
<%= text_field :age, readonly: 'true', placeholder: 'Age', class: 'form-control', disabled: 'true' %>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>Ville</label>
<%= text_field :ville, readonly: 'true', placeholder: 'Ville', class: 'form-control' %>
</div>
<div class="col-md-6">
<label>Télephone</label>
<%= text_field :telephone, readonly: 'true', placeholder: 'Telephone', class: 'form-control', disabled: 'true' %>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>Email</label>
<%= text_field :email, readonly: 'true', placeholder: 'Email', class: 'form-control' %>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>Check In</label>
<%= f.text_field :start_date, readonly: 'true', placeholder: 'Start Date', class: 'form-control' %>
</div>
<div class="col-md-6">
<label>Check Out</label>
<%= f.text_field :end_date, readonly: 'true', placeholder: 'End Date', class: 'form-control', disabled: 'true' %>
</div>
</div>
<%= f.hidden_field :voiture_id, value: #voiture.id %>
<%= f.hidden_field :prix, value: #voiture.prix %>
<%= f.hidden_field :total, id: 'reservation_total' %>
<%= f.submit "Book Now", id:"btn_book", class: "btn btn-primary wide", disabled: 'true' %>
Controller :
class ReservationsController < ApplicationController
before_action :authenticate_user!
def create
#client = Client.create(client_params)
#reservation = #client.reservations.create(reservation_params)
redirect_to #reservation.voiture, notice: "Votre reservation a bien ete cree"
end
def reservation_params
params.require(:reservation).permit(:start_date, :end_date, :prix, :total, :voiture_id)
end
def client_params
params.permit(:nom, :prenom, :cin, :age, :ville, :telephone, :email)
end
end
I'm sure there is a good and clean way to do that..
Thanks !
I would look at nested attributes for a good clean solution, here is the doc link http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
There is also a gem that can simplify it for you
https://github.com/ryanb/nested_form
Forced to ask for help with saving nested models on polymorphic association. I'm missing something but can't figure out what.
Everithing pretty straightforward. There is Address which can have multiple Phones.
So models are
class Address < ActiveRecord::Base
has_many :phones, as: :phoneable
accepts_nested_attributes_for :phones, allow_destroy: true
validates :city, :street, :building, :name, presence: true
end
and
class Phone < ActiveRecord::Base
belongs_to :phoneable, polymorphic: true
validates :number, :extension, presence: true
end
addresses_controller.rb
def new
#address = Address.new
#phone = #address.phones.build
authorize #address
end
def create
#address = Address.create(address_params)
authorize #address
if #address.save
binding.pry
flash[:success] = "Address #{#address.name} created"
redirect_to address_path(#address)
else
flash.now[:danger] = 'Failed'
render :new
end
end
def address_params
params.require(:address).permit(:name, :street, :building, :city, phones_attributes: [:id, :number, :extension, :details] )
end
/app/views/address.html.erb
<div class="row">
<div class="col-md-12">
<%= form_for(#address, html: {class: 'form-horizontal', role: 'form'}) do |f| %>
<%= render 'shared/errors', obj: #address, model_name: 'addresses' %>
<div id="create-form">
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :city, 'Город' %>
</div>
<div class="col-md-4">
<%= f.select(:city, options_for_select(['Moscow', 'Samara']), {}, {class: "form-control"}) %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :street, 'Street' %>
</div>
<div class="col-md-4">
<%= f.text_field :street, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :building, 'Building' %>
</div>
<div class="col-md-4">
<%= f.text_field :building, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :name, 'Place name' %>
</div>
<div class="col-md-4">
<%= f.text_field :name, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :phones, 'Phone' %>
</div>
<div class="col-md-4">
<%= f.fields_for :phone do |phone_form| %>
<%= phone_form.text_field :number, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= phone_form.label :extension, 'Ext.' %>
</div>
<div class="col-md-4">
<%= phone_form.text_field :extension, class: 'form-control' %>
</div>
<% end %>
</div>
<div class="form-group">
<div class='col-md-offset-4 col-md-6'>
<%= f.submit #address.new_record? ? 'Add' : 'Update', class: 'btn btn-primary btn-md' %>
</div>
</div>
</div>
<% end %>
</div>
</div>
First issue I encountered with is if I set key :phones instead :phone into the following line <%= f.fields_for :phone do |phone_form| %> my phone text fields don't render in view but they should. One user emphasized this moment here https://stackoverflow.com/a/3328041/2049476
if I use :phone everything somehow works fine but seems like it's wrong.
And the second one.
Phone object doesn't save in DB, when I create new address or edit current I succeed but phone doesn't show any validation errors if I leave all it fields blank.
Here what I have in params hash
{"utf8"=>"✓",
"authenticity_token"=>"inwXr3Ev/Aj/hZRY2IadizDHDgdSFo2zFhY9DAvysfFu3jjD9AS66esKVsTzEuKo2WC46YQt6HnOKTgInvfUEg==",
"address"=>{"city"=>"Moscow", "street"=>"ul. Tsentralnaya d. 4 kv. 220", "building"=>"1212", "name"=>"Astoria", "phone"=>{"number"=>"9215555555", "extension"=>"111"}},
"commit"=>"Add",
"controller"=>"addresses",
"action"=>"create"}
What am I missing?
Try answer for 2 issues:
The correct way is to pass :phones, and then phone as variable to field_for, like is was done here:
<%- #address.phones.each.with_index do |phone, index| %>
<%- f.fields_for :phones, phone do |phone_form| %>
<%- end %>
<%- end %>
Should be resolved as of the 1-st question, since the fields shoudl sent ot server via params not a phone hash, but phones_attributes array of hashes, in order to accepts_nested_attributes_for could accept phones:
phones_attributes: [{ ... },{ ... }]
I have a triple nested attributes that I am trying to capture all the information for in one form. In short I have an event that has many event_locations which have many event_dates which have many event_roles. I have the form in my event new. I think the issues is in my events model and I need to say that there is going other "accepts_nested_attributes_for" for event_dates and event_roles because right now in the event_params I do get the event and event_location information.
events controller
def create
#event = Event.new(event_params)
if #event.save
redirect_to #event, notice: 'Event was successfully created.'
else
render :new
end
end
private
def event_params
params.require(:event).permit(:name, :event_details, event_locations_attributes: [:label, :address, :zip, :state, :country, :notes], event_dates_attributes: [:event_date, :start_time, :end_time], event_roles_attributes: [:type, :hourly_rate, :quantity])
end
event.rb
class Event < ActiveRecord::Base
has_many :event_locations, :dependent => :destroy
has_many :event_dates, through: :event_locations
belongs_to :agency
accepts_nested_attributes_for :event_locations, :allow_destroy => true
end
event new
<h3> New Event </h3>
<%= form_for #event do |f| %>
<%= f.text_field :name, :required => true, placeholder: "Name", :maxlength => 200, class: "form-control title_input_field" %><br>
<%= f.text_area :event_details, :required => true, placeholder: "What are some of the event details", size: "100x10", class: "input_field2" %> <br>
<h3> Event Locations </h3>
<%= f.fields_for :event_locations do |builder| %>
<%= render "location_fields", :f => builder %>
<% end %>
<%= f.submit "Create!", :class => 'submit_button' %>
<% end %>
_location_fields.html.erb
<p>
<div class="row">
<div class="col-sm-5">
<%= f.text_field :label, :required => true, placeholder: "Label", :maxlength => 1000, class: "form-control title_input_field" %><br>
</div>
<div class="col-sm-5">
<%= f.text_area :notes, :required => true, placeholder: "Notes", :maxlength => 200, class: "form-control title_input_field" %><br>
</div>
</div>
<div class="row">
<div class="col-sm-5">
<%= f.text_field :address, :required => true, placeholder: "Address", :maxlength => 200, class: "form-control title_input_field" %><br>
</div>
<div class="col-sm-2">
<%= f.text_field :state, :required => true, placeholder: "State / Provience", :maxlength => 200, class: "form-control title_input_field" %><br>
</div>
<div class="col-sm-2">
<%= f.text_field :country, :required => true, placeholder: "Country", :maxlength => 200, class: "form-control title_input_field" %><br>
</div>
<div class="col-sm-2">
<%= f.text_field :zip, :required => true, placeholder: "Zip Code", :maxlength => 200, class: "form-control title_input_field" %><br>
</div>
</div>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Location" %>
</p>
<%= f.fields_for :event_date do |builder| %>
<%= render "event_date_fields", :f => builder %>
<% end %>
--
_event_date_fields.html.erb
<p>
<h3> Event Date </h3>
<div class="row">
<div class="col-sm-3">
<div class="form-group">
<div class='input-group date' id='datetimepicker1' />
<%= f.text_field :event_date, placeholder: "Select Event Date", class: "form-control", type:'text' %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div> <!-- date -->
</div> <!-- form-group -->
</div>
<div id="datepairExample">
<div class="col-sm-4">
<%= f.text_field :start_time, placeholder: "Start Time", class: 'time start form-control' %>
</div>
<div class="col-sm-1">to</div>
<div class="col-sm-4">
<%= f.text_field :end_time, placeholder: "End Time", class: 'time end form-control' %>
</div>
</div>
</div>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Date" %>
</p>
<%= f.fields_for :event_role do |builder| %>
<%= render "event_role_fields", :f => builder %>
<% end %>
In short, you need to allow all the models to allow nested attributes for their direct associations, so:
class Event < ActiveRecord::Base
has_many :event_locations, :dependent => :destroy
accepts_nested_attributes_for :event_locations, :allow_destroy => true
class EventLocation < ActiveRecord::Base
has_one :event_date
accepts_nested_attributes_for :event_date, allow_destroy: true
class EventDate < ActiveRecord::Base
has_one :event_role
accepts_nested_attributes_for :event_role, allow_destroy: true
Then your strong params should look like this:
params.require(:event).permit(:name, :event_details,
event_locations_attributes: [:label, :address, :zip, :state, :country, :notes,
event_date_attributes: [:event_date, :start_time, :end_time,
event_role_attributes: [:type, :hourly_rate, :quantity]]])