I have a parent model called user and 2 nested models called award and certification. when I go to save a certification the model validation for award tells me that awards is blank, and when I got to save an award I get an error that says the validations for certification is blank. not sure what's going on.
here my user model
has_many :certifications, dependent: :destroy
has_many :awards, dependent: :destroy
# allows for nested attributes in the user views.
accepts_nested_attributes_for :work_histories, :qualifications, :certifications, :courses, :awards,
:languages, :patents, :publications, allow_destroy: true
here my award model
class Award < ApplicationRecord
belongs_to :user
validates :award_name, :award_granted_by, :award_date, :award_description, presence: true
end
and my certification model
class Certification < ApplicationRecord
belongs_to :user
validates :certification_name, :certification_authority, :certification_number, :certification_from,
:certification_to, presence: true
end
strong params in users_controller
def user_params
params.require(:user).permit( :first_name, :last_name, :email, :phone, :current_job_title, :password, :password_confirmation,
work_histories_attributes: [:user_id, :id, :_destroy, :job_title, :company, :description, :city, :state,:start_date, :end_date],
qualifications_attributes: [:user_id, :id, :_destroy, :education, :university, :university_major, :graduation_year, :currently_enrolled, :location],
awards_attributes: [:user_id, :id, :_destroy, :award_name, :award_granted_by, :award_date, :award_description],
certifications_attributes: [:user_id, :id, :_destroy, :certification_name, :certification_authority, :certification_number, :certification_from, :certification_to, :cert_never_expires],
courses_attributes: [:user_id, :id, :_destroy, :course_name, :course_number, :course_description],
languages_attributes: [:user_id, :id, :_destroy, :language, :language_proficiency],
patents_attributes: [:user_id, :id, :_destroy, :patent_title, :patent_office, :patent_number, :patent_status, :patent_date, :patent_description],
publications_attributes: [:user_id, :id, :_destroy, :publication_title, :publication_source, :publication_date, :publication_description] )
end
here's a part of the User form. I've got a button dropdown that has several options, when a user selects an option that particular div will be shown with a modal window.
<!-- one-to-many nested attributes -->
<%= form_for(#user) do |form| %>
<!-- a partial is rendered based on the user dropdown selection -->
<div id="award">
<%= render partial: "awards/new_award_modal", locals: { form: form } %>
</div>
<div id="cert">
<%= render partial: "certifications/new_certification_modal", locals: { form: form } %>
</div>
<%= form.submit 'Save', id: "submit-achievement", class: 'btn btn-primary form-control' %>
</div><!-- modal body -->
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<% end %><!-- form_for -->
here is the partial for certifications
<div class="new_cert">
<%= form.fields_for :certifications, Certification.new do |cert_field| %>
<div class="field">
<%= cert_field.label :certification_name, 'Certification Title' %>
<%= cert_field.text_field :certification_name, class: "form-control" %>
</div>
<div class="field">
<%= cert_field.label :certification_authority %>
<%= cert_field.text_field :certification_authority, class: "form-control" %>
</div>
<div class="field">
<%= cert_field.label :certification_number %>
<%= cert_field.text_field :certification_number, class: "form-control" %>
</div>
<table>
<tr>
<td>
<div class="field">
<%= cert_field.label :certification_from, "From" %><br />
<%= cert_field.date_select :certification_from,{ :order => [:day, :month, :year],
:start_year => Date.current.year, :end_year => 1960,
:prompt => {day: 'Day', month: 'Month', year: 'Year'}, :discard_day => true }, class: 'form-control' %>
</div>
</td>
<td> </td>
<td>
<div class="field">
<%= cert_field.label :certification_to, "To" %><br />
<%= cert_field.date_select :certification_to, { :order => [:day, :month, :year],
:start_year => Date.current.year + (10), :end_year => 1960,
:prompt => {day: 'Day', month: 'Month', year: 'Year'}, :discard_day => true }, class: 'form-control' %>
</div>
</td>
</tr>
</table>
<div>
<%= cert_field.label :cert_never_expires, "This certification does not expire", class: "l" %>
<%= cert_field.check_box :cert_never_expires, class: 'cb' %>
</div>
<br />
<% end %>
</div><!-- ./new_cert -->
here's the awards partial
<div class="new_award">
<!-- nested attributes for award modal -->
<%= form.fields_for :awards, Award.new do |award_field| %>
<div class="field">
<%= award_field.label :award_name, 'Award or Honor Name' %>
<%= award_field.text_field :award_name, class: "form-control" %>
</div>
<div class="field">
<%= award_field.label :award_granted_by, "Granted by" %>
<%= award_field.text_field :award_granted_by, class: "form-control" %>
</div>
<div class="field form-inline">
<%= award_field.label :award_date, 'Date' %><br />
<%= award_field.date_select :award_date, { :order => [:day, :month, :year],
:start_year => Date.current.year, :end_year => 1960,
:prompt => {day: 'Day', month: 'Month', year: 'Year'},
:discard_day => true }, class: 'form-control ds' %>
</div>
<div class="field">
<%= award_field.label :award_description, 'Description' %>
<%= award_field.text_area :award_description, class: "form-control" %>
</div>
<% end %><!-- ./fields_for -->
</div>
so both awards and certifications can be saved to the database without any issue when there are no validations. however, when I just do a simple validation checking for presence of an attribute in the form that's when things get weird. The award model is saying that the certification form is empty, which it should be because I'm submitting the award form. And the opposite is also true, when I go to submit a certification the award validation is triggered saying the award form is blank.
It would be best to see the specific error you're getting, but I'd make sure that your form is setting the nested attributes appropriately, and that your user controller has nested attributes setup within the strong parameters.
There's documentation in the Rails guides: http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
I am building an uploader for videos and giving the videos a category through categorizations. Every time I try to upload a video I receive an error saying
NameError in VideosController#create
uninitialized constant Video::Categorization
I want to able to add one category to each video. But no regardless of how I write the association I get the same error.
model
class Video < ActiveRecord::Base
attr_accessible :source, :title, :url, :description,
:category, :category_id, :category_list
belongs_to :user
has_many :category, through: :categorizations
has_many :categorizations
validates :category, presence: true
has_attached_file :source
def source_remote_url=(url_value)
self.source = URI.parse(url_value) unless url_value.blank?
super
end
def self.categorized_with(name)
Category.find_by_name!(name).videos
end
def category_list
["Action", "Anime",
"Arts and Culture", "Beauty", "Business", "Comedy",
"Documentary", "Drama",
"Food", "Gaming", "Health and Fitness", "Horror"]
end
def category_list=(names)
self.category = names.split(",").map do |n|
Category.where(name: n.strip).first_or_create!
end
end
end
Video Controller
class VideosController < ApplicationController
before_filter :authenticate_user!
before_filter :set_video, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#videos = Video.all
end
def show
respond_with(#video)
end
def new
#video = Video.new
respond_with(#video)
end
def edit
end
def create
#video = Video.new(params[:video])
#video.save
respond_with(#video)
end
def update
#video.update_attributes(params[:video])
respond_with(#video)
end
def destroy
#video.destroy
respond_with(#video)
end
private
def set_video
#video = Video.find(params[:id])
end
end
Form
<%= form_for(#video) do |f| %>
<% if #video.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#video.errors.count, "error") %> prohibited this video from being saved:</h2>
<ul>
<% #video.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :source %><br />
<%= f.file_field :source %>
</div>
<div class="field">
<%= f.label "Category", class: 'control-label' %>
<%#= f.select :category, Category.all, :prompt => 'Select One' %>
<%= f.select :category_list, video_category, :prompt => "Select a category..." %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description, rows: 4, placeholder: "Description" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If you declare
has_many :category, through: :categorizations
it should be
has_many :categories, through: :categorizations
There are three fields in this form:
employee
project
project
The field project comes up twice and so I want two records created in this case. If I put in the values:
employee: John Doe
project: Project_1
project: Project_2
I would like two records in the model:
employee: John Doe; project: Project_1
employee: John Doe; project: Project_2
This is the view:
<%= simple_form_for(#source) do |f| %>
<div class="form-group">
<%= f.label :employee %>
<%= f.text_field :employee, class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :project, class: "form-control" %>
<%= f.input :project, class: "form-control" %>
</div>
<% end %>
Here is my code for the application controller:
def create
#source = Source.new(source_params)
if #source.save
redirect_to #source, notice: 'Source was successfully created.'
else
render action: 'new'
end
end
Any help will be greatly appreciated.
In your controller, you should build the model along with two projects, then use the form helper fields_for, which will render both project fields
your_controller.rb
class YourController
def your_action_new
#object = YourModel.new
2.times{ #object.projects.build }
end
end
For the view, I don't really know how simple_form behaves, but basically
views/your_views/new.html.erb
<!-- blabla -->
<%= f.fields_for :project do |project_f| %>
<div class="project">
<%= project_f.text_field(:name) %>
<%= project_f.text_field(:description) %>
...
</div>
<% end %>
ALso don't forget in to accept nested attributes
class YourModel
has_many :projects, dependent: :destroy
accept_nested_attributes_for :projects
end
class YourController
def your_model_params
params.require(:your_model).permit(blabla, projects_attributes: [:id, :name, :blabla, ...])
end
end
end
I'm having trouble creating a many to many model for my project.
Basically i have a Matches & Teams model.
Teams are created prior to the Matches.
Once the match is created then i would like to add teams to it.
Match can have many teams, Teams can have many matches.
I'm currently adding teams via nested_form and adding multiple teams at once.
When submitting the form, i get an error expecting the team to be in a relationship already with the match.
I can do this with a many to one relationship but it fails with many-to-many, was wondering if there was any way to do it without doing a custom route.
Below is the form, controllers are as per default values.
Form:
<%= nested_form_for(#match) do |f| %>
<% if #match.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#match.errors.count, "error") %> prohibited this match from being saved:</h2>
<ul>
<% #match.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :date %><br />
<%= f.date_select :date %>
</div>
<%= f.fields_for :teams, :html => { :class => 'form-vertical' } do |builder| %>
<%= builder.label "Team Name:" %>
<%= builder.autocomplete_field :name, autocomplete_team_name_teams_path, :update_elements => {:id => "##{form_tag_id(builder.object_name, :id)}" },:class => "input-small",:placeholder => "Search" %>
<%= builder.hidden_field :id %>
<% end %>
<%= f.link_to_add raw('<i class="icon-plus-sign"></i>'), :teams, :class => 'btn btn-small btn-primary' %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Using a join model, the has_many :through macro and the accepts_nested_attributes_for macro you can do something like the following.
class Match
has_many :competitions
has_many :teams, :through => :competitions
accepts_nested_attributes_for :teams
end
class Competition
belongs_to :match
belongs_to :team
end
class Team
has_many :competitions
has_many :matches, :through => :competitions
end
Just make sure your form is set up to send the following data structure as params when the request reaches the create or update controller.
params => {
:match => {
# ...
:teams_attributes => [
{ :name => 'Foo', :color => 'blue' },
{ :name => 'Bar', :color => 'green' },
# ...
]
}
}
I have two objects ingredient & origin.
each ingredient has an origin so in the ingredient I have origin_id
the view displays
<p>
<b>Name:</b>
<%= #ingredient.name %>
</p>
<p>
<b>Origin:</b>
<%= #ingredient.origin_id %>
</p>
class ingredient is declared as follows
class Ingredient < ActiveRecord::Base
has_and_belongs_to_many :recipes
belongs_to :origin
attr_accessible :name, :origin_id
end
class origin
class Origin < ActiveRecord::Base
attr_accessible :name
end
in the edit form I write and it works
<% originsArray = Origin.all.map { |origin| [origin.name, origin.id] } %>
<div class="field">
<%= f.label :origin_id %><br/>
<%= f.select(:origin_id, originsArray) %><br/>
</div>
but if I write instead (as in all tutorials)
<%= collection_select(:origin, :id, #origins, :id, :name, options ={:prompt => "-Select a payment"}, :class =>"origin") %>
i get
undefined method `map' for nil:NilClass
what should I fix ?
Edit
added :
def edit
#ingredient = Ingredient.find(params[:id])
#origins = Origin.all
end
I don't see here where #origins is declarated. It seems like your #origins is just nil and not collection.