Provide another model's fields for nested form in Rails - ruby-on-rails

I have a Rails app I'm building to manage a fantasy tennis bracket game.
Here are my models.
The game where the players will submit their picks:
class Game < ActiveRecord::Base
belongs_to :user
belongs_to :event
has_many :picks, dependent: :destroy
accepts_nested_attributes_for :picks
The matches where I match up two tennis players:
class Match < ActiveRecord::Base
belongs_to :event
belongs_to :player_1, class_name: "Player"
belongs_to :player_2, class_name: "Player"
has_many :picks, dependent: :destroy
The pick model.
class Pick < ActiveRecord::Base
belongs_to :game
belongs_to :match
I am using a nested form inside of another form which I have working.
<%= form_for(#game) do |f| %>
<% if #game.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#game.errors.count, "error") %> prohibited this game from being saved:</h2>
<ul>
<% #game.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :user_id %><br>
<%= f.collection_select(:user_id, User.all, :id, :name) %>
</div>
<div class="field">
<%= f.label :event_id %><br>
<%= f.collection_select(:event_id, Event.all, :id, :title) %>
</div>
<div class="field">
<%= f.label :score %><br>
<%= f.number_field :score %>
</div>
<% #matches.each do |g| %>
<%= f.fields_for :picks do |ff| %>
<fieldset>
<%= ff.label :match_id %>
<%= ff.text_field :match_id %>
<%= ff.label :winner, "Select the Winner" %>
<%= ff.text_field :winner %>
</fieldset>
<br>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I would like to use the fields from the Match model to populate the fields on the Pick model. For example, the Match has two players, I want to be able to pull the player's names into the :picks form, and will probably use an f.select on them.
I have some player data on the Match model I want to dynamically pull into the Pick model. Can't figure out how to query the database and get the field attributes to be accessed by the Pick nested form. Any help would be appreciated.

Here's what I'd do.
Get rid of "games"
Make "picks" the model to store "game" information
I think the major issue you have currently is the Game and Pick models are trying to do the same thing.
#app/models/match.rb
class Match < ActiveRecord::Base
# columns id | event_id | name | player_1 | player_2
belongs_to :event
has_many :picks
belongs_to :player_1, class_name: "Player", primary_key: :player_1
belongs_to :player_2, class_name: "Player", primary_key: :player_2
def players
[player_1, player_2]
end
end
#app/models/pick.rb
class Pick < ActiveRecord::Base
# columns id | user_id | match | winner | etc
belongs_to :user
belongs_to :match, primary_key: :match
has_one :winner, primary_key: :winner
end
This means you'll be able to do the following:
#app/views/picks/new.html.erb
<% #matches.each do |match| %>
<%= match.name %>
<%= form_for match.picks.new do |f| %>
<%= f.hidden_field :match, match.id %>
<%= f.collection_select :winner, match.players, :id, :name, prompt: "Who will win?" %>
<%= f.submit %>
<% end %>
<% end %>
#app/controllers/picks_controller.rb
class PicksController < ActionController::Base
def new
#matches = Match.all
end
def create
#pick = Pick.new pick_params
#pick.save
end
private
def pick_params
params.require(:pick).permit(:match, :winner).merge(user_id: current_user)
end
end
This will give you the ability to "pick" the players in the most simple & extensible way.

Related

Rails 4.0 nested object forms not rendered

I have two models in my app: "WorkPost" and "Contacts".
WorkPost
class WorkPost < ActiveRecord::Base
has_one :contacts
end
Contacts
class Contacts < ActiveRecord::Base
belongs_to :work_post
end
In my controller's new method I do:
def new
#work_post = WorkPost.new
#work_post.contacts
end
And in view I create form:
<%= form_for(#work_post) do |f| %>
<div class="field">
<%= f.label 'Vacation' %><br>
<%= f.text_field :post_title, :placeholder => 'Vacation here' %>
</div>
<div class="field">
<%= f.label 'Vacation description' %><br>
<%= f.text_area :post_body, :placeholder => 'Vacation description here' %>
</div>
<% f.fields_for :contacts do |cf| %>
<div class="field">
<%= cf.label 'Email' %><br>
<%= cf.text_field :emails, :placeholder => 'Email here' %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Post vacation", :class => 'btn_act' %>
</div>
<% end %>
But it seems like line <% f.fields_for :contacts do |cf| %> doesn't work.
Everything is rendered fine but email field.What I am doing wrong?
The problem is with this line
<% f.fields_for :contacts do |cf| %>
which should be
<%= f.fields_for :contact do |cf| %>
Also, the class name for the model and the association name for has_one/belongs_to should be singular.
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact #should be singular
end
#contact.rb
class Contact < ActiveRecord::Base #should be singular
belongs_to :work_post
end
Also, notice the change :contacts to :contact, as it is a has_one association.
Update:
Also, try the below changes
Include accepts_nested_attributes_for :contact in work_post.rb model
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact
accepts_nested_attributes_for :contact
end
Change the new method to below
def new
#work_post = WorkPost.new
#work_post.build_contact
end

Form for additional attributes of join model

A User has many Skills through UserSkills.
A Skill has many Users through UserSkills.
In my new user form, I'm able to add checkboxes for skills but if I add a Proficiency (string) attribtue to the UserSkills model, how can I include this?
My current code:
<%= f.label :skills %>
<%= hidden_field_tag "user[skill_ids][]", nil %>
<% Skill.all.each do |skill| %>
<%= check_box_tag "user[skill_ids][]", skill.id, #user.skill_ids.include?(skill.id), id: dom_id(skill) %>
<%= link_to skill.skilltitle, skill_path(skill.id) %>
class User < ActiveRecord::Base
has_many :user_skills
accepts_nested_attributes_for :user_skills
end
class UserSkill < ActiveRecord::Base
belongs_to :user
belongs_to :skill
accepts_nested_attributes_for :skill
accepts_nested_attributes_for :user
end
... meanwhile.. in your form
<%= form_for #user do |f| %>
<%= f.fields_for :user_skills do |f2| %>
<%# add your user_skill attributes here %>
<%= f2.check_box :proficiency %>
<%= f2.fields_for :user do |f3| %>
<%# user attributes to go here %>
<% end %>
<% end %>

rails 4 nested form fields_for are not displayed

I just started learning Rails 4.2. The problem is that one field in the form is not being displayed.
I have restaurant, category and a dish. While creating a dish, the category and restaurant will also be inputted via /dishes/new.
Expected behaviour: Dish, Category and Restaurant fields are displayed.
Actual behaviour: Only Dish and Category fields are displayed.
Here are my models
models/restaurant.rb
class Restaurant < ActiveRecord::Base
has_many :categories
has_many :dishes, :through => :categories
end
models/category.rb
class Category < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes
end
models/dish.rb
class Dish < ActiveRecord::Base
belongs_to :category
validates :name, :price, :category, :restaurant, :presence => true
accepts_nested_attributes_for :restaurant, :category
end
dish controller
def new
# I think this is where
# I am making a mistake
#dish = Dish.new
category = #dish.build_category
restaurant = category.build_restaurant
end
def create
#dish = Dish.new(dish_params)
respond_to do |format|
if #dish.save
.... # default stuff #
end
end
end
# strong params
def dish_params
params.require(:dish).permit(:name, :description, :price, restaurant_attributes: [:name], category_attributes: [:name])
end
Dishes views/dishes/_form.html.erb
<%= form_for(#dish) do |f| %>
<% if #dish.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#dish.errors.count, "error") %> prohibited this dish from being saved:</h2>
<ul>
<% #dish.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :nameWoW %><br>
<%= f.text_area :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.number_field :price %>
</div>
*** The restaurant name field is not being displayed **
<%= f.fields_for :restaurant do |restaurant| %>
<div class="field">
<%= restaurant.label :Restname %><br>
<%= restaurant.text_area :name %>
</div>
<% end %>
<%= f.fields_for :category do |category| %>
<div class="field">
<%= category.label :Catname %><br>
<%= category.text_area :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I have followed steps from rails guide, browsed questions on stackoverflow and read some blog posts as well but havent been able to figure out whats wrong. Some micro level mistake is blocking me :( . Anyone knows whats wrong ?
Thanks in advance.
UPDATE:
Hey I found a solution.
def new
#dish = Dish.new
#dish.build_category
#dish.category.build_restaurant
end
This works well.But this is just a part of the actual solution. I had to do lot of /dish/create controller modification as well. I think the entire solution will have to be put in blog post. Otherwise it wont make any sense. I will soon be posting and updating it here.
You can add this in your dish.rb
class Dish
delegate :restaurant, to: :category
end
Or you can do
<%= f.fields_for :restaurant, #dish.category.restaurant do |restaurant| %>
<div class="field">
<%= restaurant.label :Restname %><br>
<%= restaurant.text_area :name %>
</div>
<% end %>
I think you are missing:
class Dish
belongs_to :restaurant, through: :category
end
You have it on the other side (many) but not there. You could test this by trying to output #dish.restaurant on your form (should be empty but not nil).
def new
# I think this is where
# I am making a mistake
#dish = Dish.new
category = #dish.category.build
restaurant = category.restuarant.build
end

Rails Multiple Associations

I'm having trouble setting up my associations. I'm trying to set up Courses to have different Prices depending on the Season and amount of alumns. It gets even more complicated when Seasons have different date ranges for the same Season, like for instance the first Season is from 12/24/2014 to 12/31/2014 but also from 01/07/2015 to 01/14/2015. For this I created another model Season_dates.
I can't figure out how to set up my associations, here's what I have got so far:
class Season < ActiveRecord::Base
has_many :season_dates
has_many :prices, through: :season_dates
end
class SeasonDate < ActiveRecord::Base
belongs_to :price
belongs_to :seasons
end
class Price < ActiveRecord::Base
belongs_to :course
has_many :season_dates
has_many :seasons, through: :season_dates
accepts_nested_attributes_for :season_dates
end
class Course < ActiveRecord::Base
has_many :prices
end
Form:
<%= form_for #price do |f| %>
<div class="field">
<%= f.fields_for :couse do |course_f| %>
<%= course_f.label :course %><br>
<%= course_f.collection_select :course_id, Course.all, :id, :name, {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field">
<%= f.label :alumn %><br>
<%= f.number_field :alumn, in: 1...11, step: 1, class: 'form-control' %>
</div>
<div class="field">
<%= f.fields_for :season_date do |season_f| %>
<%= season_f.label :season %><br>
<%= season_f.select :season_id, options_from_collection_for_select(Season.all, :id, :name), {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field form-group">
<%= f.label :price %><br>
<%= f.number_field :price, in: 0.01..999.99, step: 0.01, placeholder: "0.00€", class: 'form-control' %>
</div>
<div class="actions">
<%= f.submit class: 'btn btn-default' %>
</div>
<% end %>
I want to be able to call price.season.name or price.course.name. I'm not sure how to proceed, any help is appreciated.
I think you might be complicating the scenario a bit. Is there a reason that SeasonDate is its own class? Is there a way you can model like this?
class Season < ActiveRecord::Base
has_many :courses
# I would have on this model the attributes of from_date and
# to_date removing the need for a SeasonDate class
end
class Course < ActiveRecord::Base
belongs_to :season
# You might need to model this as a has_and_belongs_to_many relationship
# with a Season if a Course can belong to many seasons
end
class Price < ActiveRecord::Base
belongs_to :course
belongs_to :season
end
These models would give you methods such as:
#season.courses # would return all courses in a particular season
#price.season.name
#price.course.name
#course.prices # would return all prices associated with a particular course
If you do go for the habtm association, meaning a course can belong to many seasons, you could do something like this (guessing at your price attribute names) in your views.
<%= #course.name %>
<% #course.prices.each do |price| %>
<%= price.season.name %> : <%= price.price_in_dollars %>
<% end
This would allow you to iterate over all prices for a course and display which season they are applicable for so each person can find the best price for them.

Rails uninitialized constant for an association

So there is a plethora of questions about the "uninitialized constant" error, and it's almost always due to an incorrectly specified association (e.g. plural model names instead of singular, incorrectly writing your association inside the model, etc). My models and form look spotless, so maybe this is something new (or I'm blind)?
A "user" has one "move". A "move" has many "neighborhood_preferences", and through this, many "neighborhoods".
Models:
class User < ActiveRecord::Base
has_one :move
accepts_nested_attributes_for :move, allow_destroy: true
end
class Move < ActiveRecord::Base
belongs_to :user
has_many :neighborhood_preferences
has_many :neighborhoods, through: :neighborhood_preferences
accepts_nested_attributes_for :neighborhood_preferences, allow_destroy: true
end
class NeighbhoodPreference < ActiveRecord::Base
belongs_to :neighborhood
belongs_to :move
end
class Neighborhood < ActiveRecord::Base
belongs_to :city
has_many :neighborhood_preferences
has_many :moves, through: :neighborhood_preferences
end
View:
<%= simple_form_for(#user, :html => { class: :form } ) do |u| %>
<%= u.fields_for :move do |m| %>
<div>
<%= m.label :start_date %>
<%= m.date_field :start_date %>
</div>
<div>
<%= m.label :end_date %>
<%= m.date_field :end_date %>
</div>
<div>
<%= m.label :min_price %>
<%= m.text_field :min_price %>
</div>
<div>
<%= m.label :max_price %>
<%= m.text_field :max_price %>
</div>
<%= m.association :neighborhood_preferences %>
<% end %>
<%= u.submit "Save Changes" %>
<% end %>
There is a typo in class name NeighbhoodPreference.

Resources