Error when submitting a form with two different models - ruby-on-rails

I have an office model which is a list of all the current offices. I also have a calendar model which will just act as a company calendar. I am trying to get a dropdown of all the current offices to display on the localhost:3000/calendars/new so people can see where the event will be taking place. When I go to submit the form, I get the error shown below. I have posted all relevant code as well. Thanks in advance.
Calendar.rb:
class Calendar < ActiveRecord::Base
belongs_to :office
end
Office.rb:
class Office < ActiveRecord::Base
has_many :calendars
end
calendars_controller:
def new
#calendar = Calendar.new
#offices = Office.all
end
_form.html.erb:
<div class="field">
<%= f.label :office_id, class: "general-text-label" %><br>
<%= collection_select :calendar, :office, #offices, :id, :name, {include_blank: true}, {class: "selectize"} %>
</div>
Error:
Parameters:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"lNP3u+Hs2FYsTBTClWuwJWiwW8HTFECzGVD4CdEOgOF5WD2eNiMNHtQuHjHpynJp7CaIDio09/mhvQg5rLhgtA==", "calendar"=>{"name"=>"Listing Agent Workshop", "description"=>"ffhfh", "date"=>"Friday Feb 17, 2017", "time"=>"4:00 PM", "office"=>"2"}, "commit"=>"Save"}

Rails is trying to infer which Office to associate with your new Calendar. Your calendar is being built as:
Calendar.new({"name"=>"Listing Agent Workshop", "description"=>"ffhfh", "date"=>"Friday Feb 17, 2017", "time"=>"4:00 PM", "office"=>"2"})
Rails knows the office key is an associated model but it expect the value to be an actual instance of an Office, instead here it's just a string.
Instead, you should either specify the id and let rails look it up or find the object first if that is a concern.
First way (change the params):
Calendar.new({"name"=>"Listing Agent Workshop", "description"=>"ffhfh", "date"=>"Friday Feb 17, 2017", "time"=>"4:00 PM", "office_id"=>"2"})
Better way:
office = Office.find(calendar_params[:office])
calendar_params[:office] = office
Calendar.new(calendar_params)

Related

Rails f.select Save Id an Name at the same time

I have a form with the f.select option. I want to add the Company ID and the Company Name when the company name is selected from the options. Is it possible to add multiple attributes in the f.select line of code? This is how my code looks:
<div class="field">
<%= f.label 'Client' %>
<%= f.select :client_id, Client.all.collect { |c| [ c.companyName, c.id ] } %>
I want to also assign the companyName to my :companyName attribute, but the id is the only thing that is being saved right now.
Thanks.
I think you can use associations for this. You should have 2 models as below.
class Company < ApplicationRecord
has_many :clients
end
class Client < ApplicationRecord
belongs_to :company
end
Your should use variable instead in views for rendering all clients list with this
<%= f.select :client_id, #clients.collect { |client| [ client.name, client.id] } %>
Controller:
#clients = Client.all
On Submit the client_id will be passed to controller. You can then find the company associated with the client and other logic.
client = Client.find(params[:client_id])
company = client.company
# etc ..
In the controller action where your form submits you can write before saving or updating record.
params[:your_object][:companyName]=Client.find_by(id: params[:your_object][:client_id]).companyName
Remember to a add params[:your_object][:companyName] to your strong params. e.g.
params.require(:your_object).permit(:client_id, ... , :companyName)
Before anything be sure your client_id is in same object and permitted and apply same to companyName attribute
Hope This Helps

Three text fields for one database entry for rails

I currently have one text field for a date entry, I am trying to split the year, month and day up into three individual entries, seperated by '/'. The original text entry looks like:
<%= f.text_field :date, :placeholder => 'YYYY/MM/DD' %>
I would like to split this into three text_fields, and append them together, and put it into the date entry in the database.
How can I do this?
You often use textfields for dates because you then only needs one field. When you are having three different fields should you consider using select instead. Rails have a the date helper method date_select, so it would be somethink like this:
<%= f.date_select :date %>
This creates one select for years, one for months and one for days.
You can read more on http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-date_select
Add three virtual attributes to the model:
attr_accessor :form_month, :form_day, :form_year
Then put the following in the controller, not the model:
def create
# ...
form_date = [ params[:form][:form_month], \
params[:form][:form_day] ,
params[:form][:form_year] ].join("/")
#my_model.date = Date.parse(form_date)
# ... save and return ...
end
It would be a good idea to manually check each form parameter for validity. Date#parse may spit out the incorrect date if fed an incomplete date string.
Date.parse "2005/11/4"
# => Fri, 04 Nov 2005
Date.parse "/11/4"
# => Mon, 04 Nov 2013
Try to use https://github.com/plataformatec/simple_form
<%= f.input :deadline, :start_year => Date.today.year, :end_year => Date.today.year + 1, :order => [:day, :month, :year] %>
Do you have many options.

Rails Drop Down Menu based on new Model

I've been trying to work through this for a few days and can't get anything to work. I have been building my first app based on Michael Hartl's amazing tutorial: http://ruby.railstutorial.org/. Additionally, I have tried this tutorial, but the differences in my code and his prove to be too great for me to follow along.
Where my app differs from Michael Hurtl's is that I am trying to create a site where you can post your left over cans of paint (instead of microposts, AKA twitter). When I created the app, I had a column in the Paints model called "color_family". Now I am looking to change it from a text field to a drop down with predetermined values, e.g. "Reds", Oranges", "Yellows", Greens" etc.
I started out by generating a new scaffold:
rails generate scaffold Color_Family family:string
then I generated a migration:
rails generate migration AddColor_FamilyToPaints family_id:int
and migrated it all.
Then I created the associations
class ColorFamily < ActiveRecord::Base
has_many :paints
end
and
class Paint < ActiveRecord::Base
attr_accessible :family_id, :name, :hex, :location, :quantity, :additional_info
belongs_to :user
belongs_to :color_family
...
end
This is where I get lost, and any tutorial I try to follow breaks everything. Where do I define my predetermined list of color_families?
Is it even worth it for me to go through the creation of a new model? I previously tried this in the form field:
<%= form_for(#paint) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.label :color_family %>
<%= select_tag(:color_family, options_for_select([['Red', 1],
['Orange', 2],
['Yellow', 3],
['Green', 4],
['Blue', 5],
['Purple', 6],
['Black', 7],
['Grey', 8],
['White', 9],
['Cream', 10],
['Brown', 12]])) %>
and while it created a dropdown for me, it never captured the info when I added a new paint.
Any help is greatly appreciated. Also, a link to a tutorial would probably do me the biggest help as I've very new to RoR and backend stuff in general.
I'm not sure if you are doing the reading version of the book, or the video. Personally, I recommend both! Absolutely amazing tutorial! One of the first things he does mention though, "Scaffold is not really for the real world" and you should consider this. When I'm doing projects, new old or just refactoring, I usually add everything by hand with the script/generate. The only "scaffold" I've ever used was the scaffold_controller because I was too lazy to do the controller by hand.
The short answer, you should have another model "Color" and the form should:
f.collection_select(:color_id, Color.find(:all), :id, :name, {:include_blank => 'Please Select A Color'})
And the ColorFamily should probably be a has_many_and_belongs_to_many Colors
If you could give me a run down of details associations supposed to be taking place, I can write up a small data modal for you.
Edit #1
You are needing a has_one :through relationship. The general concept will be...
Pivot tabel:
rails g migration ColorFamilyPaints paint_id:integer color_family_id:integer
Paint Class:
class Paint < ActiveRecord::Base
attr_accessible :family_id, :name, :hex, :location, :quantity, :additional_info,
:color_families_attributes # Need to add this in order for you to be able to post with drop down
belongs_to :user
...
# Creates the Relationship
has_one :color_families, :through => :color_family_paints
# Allows color families to be nested in the form.
accepts_nested_attributes_for :color_families, :allow_destroy => true
end
You'll notice a few changes. Addition to the attr_accessible, and the accepts_nested_attributes_for (you may need this, not sure with a has_one though). When you build the form, look at the ID/Name of the select box. If it ends in _attributes, use the accepts line. If not, you don't need it. Alter the :color_families_attributes to match the name of the select box.
Form HTML:
<%= form_for(#paint) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.label :color_family %>
<%= f.collection_select(:color_family, ColorFamily.find(:all), :id, :name, {:include_blank => 'Please Select Color Family'}) %>
</div>
<% end %>
More information on associations # RoR website.

Date selection with only one dropdown

I have a model articles with created_at
In my index view I want the user to be able to select all articles created in "October 2010, November 2010, December 2010, etc." with only one select dropdown.
Has anyone done this before?
Rails 3 (MySQL)
class Article < ActiveRecord::Base
...code here...
def self.article_months
group_by_clause = "to_char(created_at,'<your date format>')"
Article.group(group_by_clause).select("#{group_by_clause} as month, count(*) as count").order(created_at desc).all
end
...code here...
end
In your view, use select_tag or collection_select or something and render the collection above.
In my controller I did:
#startdates = ActiveRecord::Base.connection.select_rows("SELECT DISTINCT MONTH(start_date), YEAR(start_date) FROM schedules WHERE event_id IN (#{#events.map{|n| n.id}.join(',')}) ORDER BY start_date ASC;")
and in my view:
<%= select(:event, :startdate, #startdates.map{|s| ["#{t("date.month_names")[s[0].to_i]} #{s[1]}", "#{s[1]}-#{s[0]}"]}, {:selected => #startdate.to_s, :include_blank => "All"}) %>

Modifying attributes on the join model with accepts_nested_attributes_for

Simply, a Contact can have various associated Time Windows, which may or may not be Active as a Schedule. To wit:
Models
class Contact < ActiveRecord::Base
has_many :schedules
has_many :time_windows, :through => :schedules
accepts_nested_attributes_for :schedules, :allow_destroy => true
end
class TimeWindow < ActiveRecord::Base
has_many :schedules
has_many :contacts, :through => :schedules
end
class Schedule < ActiveRecord::Base
belongs_to :contact
belongs_to :time_window
end
View
<% TimeWindow.all.each do |tw| %>
<% schedule = Schedule.find_by_contact_id_and_time_window_id(#contact.id, tw.id)
schedule ||= Schedule.new %>
<p>
<%= f.label tw.description %>
<%= hidden_field_tag "contact[schedules_attributes][][id]", schedule.id %>
<%= check_box_tag "contact[schedules_attributes][][time_window_id]",
tw.id, #contact.time_windows.include?(tw) %>
<%= check_box_tag "contact[schedules_attributes][][active]", nil,
schedule.active %>
</p>
<% end %>
This submits something like this:
Parameters: { "commit" => "Update", "contact" => {
"group_ids" => ["2"], "enabled" => "1",
"schedules_attributes" => [ { "time_window_id"=>"1", "id"=>"46"},
{ "time_window_id" => "2", "id" => "42", "active" => "on" },
{ "time_window_id" => "3", "id" => "43"},
{ "time_window_id" => "4", "id" => "44", "active" => "on"}],
"last_name" => ...
The update action in the controller is basically stock, except to handle another instance of another related model which I coded using the "Handling Multiple Models" example from the Advanced Rails Recipes book.
According to this API doc, I think the above ought to work. However, nothing about the Schedules is getting updated. This shows up in the server log:
[4;35;1mSchedule Update (0.2ms)[0m [0mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 42[0m
[4;36;1mSchedule Update (0.1ms)[0m [0;1mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 44[0m
(NetBeans is giving me those stupid "[0m"'s in the output. I don't know what's wrong there.)
The SQL shows that the "active" boolean field is getting set to 0 where checked. How do I get this to correctly set the active bit?
As a followup, how would I organize this to get rid of the Schedule "connection" at all? I'm thinking I need to submit a :_delete with the Schedule from the form, but how would I do that conditionally when a checkbox is involved?
Thanks for any help you can provide. Rails is turning out to be a vast subject for me, and I want to do it "right." I'm really close here, but there's got to be a way to make this -- not just correct -- but elegant. The view code just feels way too cumbersome to be proper Rails. ;-)
I've kept trying different approaches to this problem, and I've come up with this, which works. Mostly. The only problem is that it doesn't handle NOT having a "Schedule" for each "Time Window". The form will render, and I'll get a disabled check_box (to prevent me from trying to delete something that isn't there), but I don't have a way to add it back, and submitting without it throws off the params hash (and causes Rails to give me an "Expected Hash (got Array)" error)
<% TimeWindow.all.each do |tw| %>
<% schedule = Schedule.find_by_contact_id_and_time_window_id(#contact.id, tw.id)
schedule ||= Schedule.new %>
<% f.fields_for "schedules_attributes[]", schedule do |sf| %>
<p>
<%= sf.label tw.description %>
<%= sf.hidden_field :id %>
<%= sf.check_box :_destroy, :disabled => schedule.new_record? %>
<%= sf.check_box :active %>
</p>
<% end %>
<% end %>
Note that the "schedules_attributes[]" array will automatically give you an existing ID within the braces in your HTML (which is nice), but the _attributes hash is expecting an "id" alongside the other attributes in order to make sense of the sub-hashes.
One of the big lessons I've learned here is that the "check_box_tag" method doesn't (seem to) give me a paired-up hidden field for Rails to parse in the unchecked case. I would have expected this. Adding one in by hand made a mess, which led me to finally giving into the "fields_for" method, and trying many incarnations before finding the appropriate syntax to get what I wanted out of it.
I've realized that my model isn't quite appropriate in this setup, so I'm going to change it, but I was so close to this answer, I wanted to at least get to the point of being able to see the end before I moved on.

Resources