Populate Rails Form With Model Information From Another Controller - ruby-on-rails

I've renamed the SessionsController and Session Model to Periods/Period because it conflicted with Devise and so you'll see this in the update
I have a sessions and events model/controller. When a new session is created, it needs to be associated with a particular event.
In my sessions model, I have an event_id, but I want to have a dropdown on the form that is populated with name of non-past events. Once that is selected, the form should be able to assign the correct event_id to the created session.
What is the correct way to go about doing this?
Here is my schema.rb to help you get a clearer picture of what the Models look like:
ActiveRecord::Schema.define(:version => 20120807154707) do
create_table "events", :force => true do |t|
t.string "name"
t.date "date"
t.string "street"
t.string "city"
t.string "state"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "sessions", :force => true do |t|
t.string "name"
t.integer "event_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "admin", :default => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
end
Here is my form:
<%= form_for(#period) do |f| %>
<%= f.label :Name %>
<%= f.text_field :name%>
<%= f.label :Event %>
<%= f.collection_select(:period, :event_id, Event.all, :id, :name)%>
<%= f.label :time %>
<%= f.text_field :time, id: "timepicker" %>
<%= f.submit "Create Event" %>
<% end %>
and I keep getting the following error: undefined methodmerge' for :name:Symbol`
Breaking out the various arguments of collection select: f.collection_select(:period, :event_id, Event.all, :id, :name)
:period -> The object
:event_id -> the method I want to set on the object.
Event.All -> The collection (for now I'll take all of them)
:id -> the value of the html element option
:name -> the value displayed to the user
Am I doing that correct?

To display a select menu with options from another model (not another controller), try collection_select.
In your new Session form, this might look like:
collection_select(:event, :id, Event.where("date > :date", date: Time.now.strftime("%m/%d/%Y"))
In the Sessions controller, in the create action, build the association like this:
#session.event = Event.find(params[:event][:id])

I have found that this structure works for me:
<%= f.label :event %>
<%= f.collection_select :event_id, Event.all, :id, :name, {:prompt=> "Pick an Event"}, {:class => "form-control"} %>
The last bit was the html part which I used to set the Bootstrap class.
:name here could be :date or :street etc...

Related

Rails 6 Complex Form with nested objects collection_select not working

Would be super grateful if anyone had any insights into what I should be doing that I'm not already doing.
db/schema.rb
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password_digest"
t.bigint "cell_number"
t.boolean "sms_daily"
t.string "initials"
t.string "remember_token"
t.boolean "admin", default: false
t.boolean "vacation_mode", default: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "remember_digest"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["remember_token"], name: "index_users_on_remember_token"
end
create_table "schedules", force: :cascade do |t|
t.text "comments"
t.integer "author_id", null: false
t.boolean "draft", default: true
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["author_id"], name: "index_schedules_on_author_id"
end
create_table "rooms", force: :cascade do |t|
t.integer "schedule_id", null: false
t.integer "order"
t.string "site"
t.string "note"
t.string "name"
t.integer "start_hour"
t.integer "start_minute"
t.string "user_initials"
t.boolean "block"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["schedule_id"], name: "index_rooms_on_schedule_id"
end
app/model/schedule.rb
class Schedule < ApplicationRecord
belongs_to :author, class_name: "User"
has_many :rooms
accepts_nested_attributes_for :rooms
...
end
app/model/room.rb
class Room < ApplicationRecord
belongs_to :schedule
...
end
app/views/schedule/new.hthl.erb
<% provide(:title, 'Create Schedule') %>
<h1>Create Schedule</h1>
<div class="row">
<aside class="span4">
<section>
<%= form_with(model: #schedule, local: true) do |f| %>
<div class="field">
<%= f.fields_for :rooms, html: {class: 'form-inline' } do |r| %>
<div class="room-title" id="<%="#{r.object[:site]}-#{r.object[:name].delete(' ')}" unless r.object[:name] == nil %>">
<%= "#{r.object[:site]} #{r.object[:name]}"%>
<%= r.hidden_field :site, value: r.object[:site] %>
<%= r.hidden_field :name, value: r.object[:name] %>
<% unless (r.object[:name] == "CHARGE" || r.object[:name] == "CO-CHARGE" || r.object[:site] == "ON_CALL" || r.object[:site] == "On-Call TODAY (Sunday or Holiday)") %>
<br/>
<%= r.label :start_hour %>
<%= r.number_field :start_hour, in: 0..24, step: 1 %>
<br/>
<%= r.label :start_minute %>
<%= r.number_field :start_minute, in: 0..60, step: 1 %>
<% end %>
<%= r.collection_select(:user_initials,User.all.map(&:initials).sort.unshift("-- late start").collect,:initials,:initials, include_blank: true) %>
</div>
<% end %>
<%= f.submit "Save Schedule and Review", class: "btn btn-large btn-primary", input_html: { :tabindex => autotab } %>
</div>
<% end %>
</section>
</aside>
</div>
I'd like for the form to present a choice of all the User's initials to be assigned to the room's user_initials, also offer the choice of not designating anyone's initials with "-- late start" as well as leaving the initials blank for an empty room.
When I deploy my code to heroku the schedule/new page generates a "We're sorry, something went wrong" error and the logs say:
ActionView::Template::Error (undefined method `initials' for "-- late start":String):
I got this all working in Rails 4 using simple_form but heroku will no longer support the stack that I deployed the site to starting in November, 2020, and heroku's new stack's won't use the old ruby version from the original site. I'm rewriting the code in Rails 6 which simple_form doesn't work for.
Thanks in advance for your consideration!
collection_select works on a collection of objects and will look for the initials method on each object.
when you do this...
<%= r.collection_select(:user_initials,User.all.map(&:initials).sort.unshift("-- late start").collect,:initials,:initials, include_blank: true) %>
You're just creating an array of strings, and you're prepending another string to the array, and the strings don't have an initials method.
Better might be just to use select
<%= r.select(:user_initials, options_for_select(User.all.pluck(:initials).sort.unshift("-- late start"), r.object.user_initials), include_blank: true) %>
You can use collection_select, it must be ALL user objects, so you could temporarily create a user with initials '--late start', something like...
<%= r.collection_select(:user_initials, User.order(:initials).to_a.prepend(User.new(initials: "-- late start")), :initials, :initials, include_blank: true) %>

Creating a drop down list from another table in rails

I am trying to add a relational field drop down select to the existing table. My current Schema
create_table "hardwares", force: :cascade do |t|
t.string "serialnumber"
t.string "modelnumber"
t.string "modeltype"
t.string "location"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "poc_id"
t.index ["poc_id"], name: "index_hardwares_on_poc_id"
end
create_table "pocs", force: :cascade do |t|
t.string "name"
t.string "address"
t.string "facility"
t.string "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The index field in the hardwares table was created when I ran the migration.
rails g migration addPocReferencesToHardwares poc:references
which generated the migration file below as well as the index in the schema
class AddPocReferencesToHardwares < ActiveRecord::Migration[5.1]
def change
add_reference :hardwares, :poc, foreign_key: true
end
end
After setting up the relationship, I would like to be able to select a POC for the hardware by name as a drop down of all available POC's.
I added this to the Hardware form:
<div class="field">
<%= form.label "POC" %>
<%= form.collection_select(:poc_id, Poc.all, :id, :name, { :prompt => 'Select a POC', :selected => #poc.poc_id }, { class: 'form-control' }) %>
</div>
The error I get is " undefined method `poc_id' for nil:NilClass". How do I allow a drop down selection for adding a POC to the hardware?
Issue was the fact that I had set the relationship as POC belongs to Hardware, thus in the Form field it needed to be:
<div class="field">
<%= form.label "POC" %>
<%= form.collection_select(:poc_id, Poc.all, :id, :name, { :prompt => 'Select a POC', :selected => #hardware.poc_id }, { class: 'form-control' }) %>
</div>

How to have a select_tag drop down to associate items with lists

I have Item and List models and they are both associated. List has_many items and an item belongs_to a list
Schema:
create_table "items", force: :cascade do |t|
t.string "name"
t.integer "list_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "completed", default: false
end
create_table "lists", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "permission", default: "private"
end
I want to create a view (most likely items/new.html.erb) so when a user creates a new item, there will be a drop-down option for the user to select which list it belongs to. There will be a pre-defined list in the beginning (i.e.: List name: "Home", "Work", "Personal"). Any item that user makes will be associated to either one of those three.
Right now I have an Item new.html.erb view that takes in simple item name and list_id.
<%= form_for #item do |f| %>
<%= f.label :name %><br>
<%= f.text_area :name, size: "24x12" %><br>
<%= f.label :list_id %><br>
<%= f.text_field :list_id %><br>
<%= f.submit %>
<% end %>
Entering list_id manually is very inconvenient; after researching, it seems like select_tag is the best form helper to do the job.
How can I build a select_tag that displays 3 drop-down List that a user can choose from to associate an Item to List?
you can also use select since you use form to achieve this. since you mentioned List name are pre-defined you can do it like this:
<%= f.select :list_id, options_for_select([['Home', 1], ['Work', 2], ['Personal', 3]]), {:include_blank => true} %>
Note: ['Home', 1] home has an id of 1 here {:include_blank => true} to include blank.

rails - form_for - how to have my 'Property' form update the 'Ticket' model?

I have 3 tables- OwnerofProperty , Property and Ticket. I want to make a form using form_for to represent property booking; can I make a form to retrieve data from Property where the submit button saves the data in the Ticket table? I am asking because I have no idea if that can be possible or how to make it.
Note: I have only created the relations :
OwnerofProperty one-to-many Property
Property one-to-one Ticket
I need this form just to make a user able to see the avaliable properties and can book only one , how to make this form ?
Schema.rb for the three models :
create_table "owners", :force => true do |t|
t.string "f_name"
t.string "l_name"
t.string "address"
t.string "tel_no"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "properties", :force => true do |t|
t.string "p_street"
t.string "p_city"
t.string "postcode"
t.string "property_type"
t.integer "rooms"
t.integer "rent"
t.integer "owner_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "properties", ["owner_id"], :name => "index_properties_on_owner_id"
create_table "tickets", :force => true do |t|
t.string "city"
t.string "street"
t.string "ticket_type"
t.integer "rooms"
t.integer "rent"
t.integer "property_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "tickets", ["property_id"], :name => "index_tickets_on_property_id"
Yes, it is possible.
let's see ticket_controller.rb
def new
#property = Property.find 20 #20 is property id
#properties = Property.all
##ticket = Ticket.new
end
now in view (where you want to create form):
<%= form_for #ticket do |f| %>
<%= f.select :property_id, #properties.collect {|p| [ p.name, p.id ] }%> <!-- just an example, Ticket model has a field named "property_id" -->
<%= f.submit %>
<%= end %>
this form submits to create action of ticket_controller. And you are able to get all data as params and save it to table.
def create
#ticket = Ticket.new(params[:ticket])
#ticket.save
respond_to do |format|
format.html{redirect_to( your_desired_path)}
end
end

Belongs_to only recognized by console, not server

I've got a really weird problem with my project. I've got 2 models, the one is Link and the other Category. I've got a index view where all the links should be listed, together with the corresponding category names. When running the server and trying to use
<%= link.category.name %>
I get an error page with the following:
undefined method `name' for nil:NilClass
But when I open the console and write:
link = Link.find(1) #there is currently only one link
link.category.name
It returns the correct category name.
Here are my Models and schema.rb:
class Link < ActiveRecord::Base
attr_accessible :category_id, :description, :title, :url, :visible
belongs_to :category
scope :visible, lambda { where(visible: true) }
end
.
class Category < ActiveRecord::Base
attr_accessible :name
has_many :links
end
.
ActiveRecord::Schema.define(:version => 20130420070717) do
create_table "categories", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "categories", ["id"], :name => "index_categories_on_id"
create_table "links", :force => true do |t|
t.string "title"
t.text "description"
t.string "url"
t.integer "category_id"
t.boolean "visible"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "links", ["category_id"], :name => "index_links_on_category_id"
add_index "links", ["id"], :name => "index_links_on_id"
end
How can this happen? Thank you very much for your help!
Maybe I can help others facing the same issue.
The category_id was assigned to the link by a form which queries the existing categories from the db.
<%= f.select(:category_id, #categories.collect { |c| c.name }) %>
The category I wanted to assign has the id = 1. After selecting the category from the dropdown menu, the link.category_id was 0, it should have been 1.
UPDATE:
I fixed the wrong index by:
<%= f.collection_select :category_id, #categories, :id, :name, :prompt => "Select a category" %>

Resources