Still learning rails and have been stuck on this for a while, I have a feeling it's a simple fix and I'm just not getting it.
I'm trying to use a separate model to populate a dropdown in another model's form. So a nested form. It is the type of activity done in a workout.
Here's what I have set up.
Workout Model
class Workout < ActiveRecord::Base
belongs_to :user
has_many :activities
accepts_nested_attributes_for :activities
validates :activity, presence: true
end
Workout Controller Params
def workout_params
params.require(:workout).permit(:rating, :activity, :workout_date, :activity_id, activity_params:[:id, :title])
end
Activity Model
class Activity < ActiveRecord::Base
belongs_to :workout
end
Activity Controller Params
def activity_params
params.require(:activities).permit(:title, :rating, workout_params:[:id])
end
View
<%= form_for(#workout) do |f| %>
<div class="control-group">
<%= f. label :activity, class: 'control-label' %>
</div>
<div class="checkbox">
<%= collection_select( :activity, :workout_id, Activity.all, :id, :title, {},
{:multiple => false }) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Thanks in advance
Fixed it. Error was in the view > collection_select. The order was wrong and i changed :activity_id to :activity
<%= collection_select :workout, :activity, Activity.all, :id, :title, {}, {:multiple => false } %>
Related
I have a model called timesheet. i wanted to have a nested form for this timesheet model. means i do not want to add any child models to it. Basically i want to have nested form for single model(timesheet).
when i click add button another form should come to the parent model(timesheet) similarly when we click remove the form should be removed. how can i do this? is there any gem to do this ?
i am using the self referential association.
getting the error:Invalid association. Make sure that accepts_nested_attributes_for is used for :log_times association.
<%= nested_form_for(#log_time, html: {:class => 'form-inline'}) do |f| %>
<%= f.label :date %>
<%= f.date_select :date, { order: [:day, :month, :year] } ,{:class => 'form-control' } %>
<%= f.fields_for :log_time do |details| %>
<%= details.label :date %>
<%= details.date_select :date, { order: [:day, :month, :year] } ,{:class => 'form-control' } %>
<%= details.link_to_remove "<i class='fa fa-minus'></i>Remove".html_safe,:class=>"btn btn-danger btn-sm" ,:style=>"color: white;"%>
<%end %>
<%= f.link_to_add "<i class='fa fa-plus'></i>Add".html_safe, :log_times, :class=>"btn btn-primary btn-sm", :id=>"",:style=>"" %>
<%= f.button "Submit" ,:class=>"btn btn-primary btn-sm" do%>
<i class='fa fa-send-o'></i>Submit
<%end%>
<% end %>
Add a self-referential association to your timesheet model:
class Timesheet < ActiveRecord::Base
belongs_to :parent, class_name: 'Timesheet'
has_many :children, class_name: 'Timesheet', foreign_key: 'parent_id'
accepts_nested_attributes_for :children
end
In the controller you can do:
#timesheet = Timesheet.new
#timesheet.children.build
When I submit the form it is passing {"utf8"=>"✓", "authenticity_token"=>"blah", "client"=>{"first_name"=>"jack", "last_name"=>"kool","complaints"=>{"symptom"=>"burnt"} in the params and I am getting Unpermitted Parameters: complaints Since complaints is nested in Client, it should be passing complaints_attributes, like I have it set up in the strong params, and I can't figure out why it isn't.
class ClientsController < ApplicationController
def new
#client = Client.new
end
def edit
#client = Client.find(params[:id])
end
def create
#client = Client.new(client_params)
if #client.save
redirect_to #client
else
render 'new'
end
end
def update
#client = Client.find(params[:id])
if #client.update(client_params)
redirect_to #client
else
render 'edit'
end
end
private
def client_params
params.require(:client).permit(:first_name, :last_name, complaints_attributes: [ :symptom, :id ])
end
end
Client model:
class Client < ActiveRecord::Base
has_many :complaints
has_one :personal_disease_history
has_one :family_disease_history
has_many :surgeries
has_many :hospitalizations
has_many :medications
has_many :allergies
validates :first_name, :last_name, presence: true
accepts_nested_attributes_for :complaints
end
Complaint model:
class Complaint < ActiveRecord::Base
belongs_to :client
end
Form:
<%= form_for :client, url: clients_path, html: { class: "form-inline" } do |f| %>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Health History Form</h3>
</div>
<div class="panel-body">
<div class="form-blocks"><legend>Name</legend>
<div class="form-group">
<%= f.label :first_name, class: "sr-only" %>
<%= f.text_field :first_name, class: "form-control", placeholder: "First Name" %>
</div>
<div class="form-group">
<%= f.label :last_name, class: "sr-only" %>
<%= f.text_field :last_name, class: "form-control", placeholder: "Last Name" %>
</div>
</div>
<div class="form-blocks"><legend>Complaints</legend>
<div class="form-group">
<%= f.fields_for :complaints do |builder| %>
<%= builder.label :symptom, class: "sr-only" %>
<%= builder.text_field :symptom, class: "form-control", placeholder: "Symptom" %>
<% end %>
</div>
</div>
<div>
<%= f.submit "Submit Form", class: "btn btn-primary btn-lg"%>
</div>
<% end %>
inside client controller create action, try saying this inside the if #client.save:
Complaint.create(symptom: params[
"client"]["complaints"]["symptom"], client_id: #client.id)
the unpermitted parameter is related to the nested attribute problem but this should get the actual record saving. If that doesn't do it, please post the stack trace surrounding the commit.
have couple other ideas: but (1) you have complaint_attributes in the permitted params but you could change that to complaint bc that's what's coming through in the params.
what i want to accomplish it's almost exactly the same as this!
railscast tutorial but can't get it to work.I have a courses table and a enrollments table they have a many to many relation so i have a join table called "courses_enrollments" i'd like to be able to add many courses to enrollments all at once from a form... i used a has_many_through relation and looped through all the courses in the form and for each of them i have a checkbox so i can add them to enrollments but when i save nothing happens my join table (courses_enrollments) never gets filled with the relations i want.... here are my models:
courses:
class Course < ActiveRecord::Base
has_many :courses_enrollments
has_many :enrollments, :through => :courses_enrollments
enrollments:
class Enrollment < ActiveRecord::Base
has_many :courses_enrollments
has_many :courses, :through => :courses_enrollments
and courses_enrollments:
class CoursesEnrollment < ActiveRecord::Base
belongs_to :courses
belongs_to :enrollments
end
and finally my enrollments form view:
<%= form_for(#enrollment) do |f| %>
<% if #enrollment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#enrollment.errors.count, "error") %> prohibited this enrollment from being saved:</h2>
<ul>
<% #enrollment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :state %><br>
<%= f.collection_select(:state, Courses.all, :id, :name, {:include_blank => true}, {:multiple => false}) %>
</div>
I also tried it like this in the form.... but nothing gets saved here either
<% Courses.all.each do |course|%>
<%= check_box_tag "enrollment[course_id][]", course.id %>
<%= course.name %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
i want to be able to save many records to the join table that holds the relation between the enrollments i am creating or updating and the courses i selected with the has many through association.... appreciate the help
Models:
class Course < ActiveRecord::Base
has_and_belongs_to_many :enrollments
class Enrollment < ActiveRecord::Base
has_and_belongs_to_many :courses
with this type of association you end up with a join table which will have course_id and enrollment_id . Thus not needing to create a new model just to handle your association. Rails already does that for you.
After that, in your controllers, make sure the accepted_params have this:
Controllers:
def course_params
params.require(:course).permit(
...
enrollments_ids: []
def enrollment_params
params.require(:enrollment).permit(
...
courses_ids: []
I am trying to incorporate Simple_forms into my app using a virtual attributes. I am following http://railscasts.com/episodes/102-auto-complete-association-revised to get autocomplete to work as well. Simple_form works when i do not use a virtual attribute but when I do use the virtual attribute I get the error "Association :head_coach_name not found".
My Team Model is:
class Team < ActiveRecord::Base
attr_accessor :head_coach_name
belongs_to :user
validates :team_name, presence: true
belongs_to :head_coach, class_name: "User", :foreign_key => "head_coach_id"
def head_coach_name
user.try(:name)
end
def head_coach_name=(name)
self.user = User.find_by_name(name) if name.present?
end
end
My User model is:
class User < ActiveRecord::Base
has_many :teams, :class_name => "::Team", dependent: :destroy
end
My View:
<%= simple_form_for #team, html: {class: 'form-horizontal' }, url: teams_path, method: 'post' do |f| %>
<%= f.error_notification %>
<%= f.hidden_field :user_id %>
<div class="col-md-6">
<div class="row">
<div class="col-md-12">
<%= f.input :team_name, class: "form-control" %>
<%= f.input :year, collection: Date.today.year-90..Date.today.year %>
<%= f.input :season, as: :select, collection:
['Fall',
'Winter',
'Spring',
'Summer'] %>
<%= f.input :season_type, as: :select, collection:
['Outdoor',
'Indoor',
'Tournament'] %>
<%= f.input :awards %>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-12">
<%= f.input :club %>
<%= f.input :division %>
<%= f.association :head_coach_name %>
<%= f.input :assistant_coach_id %>
<%= f.input :assistant_coach_two_id %>
</div>
</div>
</div>
<%= f.button :submit, label: "Add team", class: "btn btn-large btn-primary col-md-3 pull-right" %>
<% end %>
Everything works as long as i don't have the virtual association in there. I could put :head_coach and it would work with a drop down list but I want to use the autocomplete feature like in the railscast video. Also in rails console i can run these commands to show the virtual attribute works:
2.1.2 :003 > team.head_coach_name
User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 100 LIMIT 1
=> "Miss Daisha Shanahan"
Any ideas on how I can get the virtual attribute to work correctly with simple_forms?
You are referencing an association that doesn't exist with f.association :head_coach_name. Try this instead:
f.association :head_coach, label_method: :head_coach_name
You have a few other oddities in your code, including your head_coach_name definition, which should rely on head_coach instead of user. Same concern for the head_coach_name= method.
Example. You have:
def head_coach_name
user.try(:name)
end
Seems like you should have:
def head_coach_name
head_coach.try(:name)
end
Hoping someone can suggest a fix here. I am fairly new to Rails, and exploring the changes in Rails 4.0. I built this simple recipe book app in Rails 4.0. I have a main model for recipes (name, cook_time, oven_temp, instructions, etc.). Because some recipes may have 5 ingredients and others may have 20, I wanted to break ingredients out in a separate model with a has_many association. So Recipes has_many Ingredients and accepts_nested_attributes_for :ingredients. Here are the models:
recipe.rb
class Recipe < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :ingredients, :dependent => :destroy
validates :name, presence: true, length: { maximum: 50 }
accepts_nested_attributes_for :ingredients,
:reject_if => lambda { |a| a[:name].blank? },
:allow_destroy => true
end
ingredient.rb
class Ingredient < ActiveRecord::Base
belongs_to :recipe
end
Reminder: Rails 4.0 no longer uses attr_accessible, but moves assignment into the controller with strong params.
recipes_controller.rb
class RecipesController < ApplicationController
before_action :find_recipe, only: [:show, :edit, :update, :destroy]
before_action :set_current_user, except: [:index, :show]
respond_to :html, :js
...
def edit
end
def update
if #recipe.update_attributes(recipe_params)
redirect_to #recipe
else
render :edit
end
end
...
def find_recipe
#recipe = Recipe.find(params[:id])
end
private
def recipe_params
params.require(:recipe).permit( :id, :name, :category_id, :cook_time, :oven_temp, :calories, :instructions, :notes, :email, ingredients_attributes: [:id, :name])
end
end
I'm using the excellent Cocoon gem from nathanvda to manage nested form fields dynamically, and it works great in 'recipes#new', and saves the information correctly. However, the ingredients fields do not appear in the 'recipes#edit' view! Here is the code for my 'form' and ingredients_fields partials.
_form.html.erb (abbreviated)
<%= form_for #recipe, html: { class: 'form-horizontal' } do |f| %>
<fieldset>
<legend>Main Information</legend>
<div class="field form-group">
<%= f.label :name, "Recipe name", class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_field :name, class: "form-control" %>
</div>
</div>
<div class="field form-group">
<%= f.label :cook_time, class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_field :cook_time, class: "form-control" %>
</div>
</div>
...
</fieldset>
<legend>Ingredients</legend>
<p>Number of ingredients: <%= f.object.ingredients.count unless f.object.ingredients.nil? %></p>
<fieldset id="ingredients">
<% f.fields_for :ingredients do |builder| %>
<%= render 'ingredient_fields', :f => builder %>
<% end %>
<p class="links">
<%= link_to_add_association 'add ingredient', f, :ingredients, { class:"btn btn-primary" } %>
</p>
</fieldset>
<fieldset>
<legend>How to make it</legend>
<div class="field form-group">
<%= f.label :instructions, class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_area :instructions, class: "form-control", rows: "7" %>
</div>
</div>
...
</div>
</fieldset>
<% end %>
_ingredients_fields.html.erb
<div class="nested-fields">
<div class="form-group">
<%= f.label :name, "Ingredient", class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_field :name, class: "form-control" %>
</div>
<%= link_to_remove_association "remove", f %>
</div>
</div>
As I said, pretty simple, removed all error checking and messaging, just the basics. Any ideas about what I am missing? I know there are ingredients in the recipe as I load edit from a show view. Thanks in advance for any advice!
Kevin
Ack. it was as simple as an '=' sign - must have looked at the <% f.fields_for... %> a thousand times and just didn't notice I'd missed adding the <%=.
<%= f.fields_for :ingredients do |builder| %>