Saving model associations in the controller - ruby-on-rails

I have the following models set up:
class Player < ActiveRecord::Base
has_many :game_players
has_many :games, :through => :game_players
end
class Game < ActiveRecord::Base
has_many :game_players
has_many :players, :through => :game_players
end
class GamePlayer < ActiveRecord::Base
belongs_to :game
belongs_to :player
end
Each Game has four players. I need some guidance in the controller for what saving a new game and it's 4 players in the GamePlayer model would look like. This is what I have in my controller so far:
# POST /games
# POST /games.xml
def create
#game = Game.new(params[:game])
respond_to do |format|
if #game.save
format.html { redirect_to(#game, :notice => 'Game was successfully created.') }
format.xml { render :xml => #game, :status => :created, :location => #game }
else
format.html { render :action => "new" }
format.xml { render :xml => #game.errors, :status => :unprocessable_entity }
end
end
end
Obviously it's only saving the Game model but it is unclear to me how to go about creating and saving the 4 players in GamePlayer. GamePlayer is really just supposed to have a game_id and player_id with some extra meta data for each row (like who played defense, etc.).
Any help would be appreciated.
In my view form I have the following:
<%= 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 |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :blue_score %> :
<%= f.text_field :blue_score %><br />
<%= f.label :white_score %> :
<%= f.text_field :white_score %><br />
<%= label_tag(:white_offense, "White Offense:") %>
<%= select_tag "white_offense", options_from_collection_for_select(#players, "name", "id")
<%= select_tag "white_defense", options_from_collection_for_select(#players, "name", "id")
<%= select_tag "blue_offense", options_from_collection_for_select(#players, "name", "id")
<%= select_tag "blue_defense", options_from_collection_for_select(#players, "name", "id")
<%= submit_tag("New Game") %>
</div>
<% end %>

Although I feel like there has to be a better way than this (perhaps using Collections?), here are is my solution:
<%= label_tag(:white_offense, "White Offense:") %>
<%= select_tag "white_offense", options_from_collection_for_select(#players, "id", "name") %>
<br />
<%= label_tag(:white_defense, "White Defense:") %>
<%= select_tag "white_defense", options_from_collection_for_select(#players, "id", "name") %>
<br />
<%= label_tag(:blue_offense, "Blue Offense:") %>
<%= select_tag "blue_offense", options_from_collection_for_select(#players, "id", "name") %>
<br />
<%= label_tag(:blue_defense, "Blue Defense:") %>
<%= select_tag "blue_defense", options_from_collection_for_select(#players, "id", "name") %>
<br />
<%= submit_tag("New Game") %>
And my controller:
#game = Game.new(params[:game])
#game.game_players.build(:player_id => params[:white_offense])
#game.game_players.build(:player_id => params[:white_defense], :is_defender => 1)
#game.game_players.build(:player_id => params[:blue_offense], :is_blue => 1)
#game.game_players.build(:player_id => params[:blue_defense], :is_blue => 1, :is_defender => 1)

Related

collection_select not inserting value from other model

I have two models, Roaster and Roast
I want to have the user select the value of :roaster in the new roast form, from the Roaster model. I am using a collection_select which displays the list of roasters in the dropdown ok, but it doesn't insert the value into the table. From the console, it actually looks like it's trying to pass the roaster_id
"roast"=>{"roaster_id"=>"1", "name"=>"Rugby", "beans"=>"", "countries_attributes"=>{"0"=>{"country_name"=>"", "regions_attributes"=>{"0"=>{"region_name"=>""}}}, "1"=>{"country_name"=>"", "regions_attributes"=>{"0"=>{"region_name"=>""}}}, "2"=>{"country_name"=>"", "regions_attributes"=>{"0"=>{"region_name"=>""}}}}, "bestfor"=>"", "roast"=>"", "tastingnotes"=>""}, "commit"=>"Create Roast"}
My select:
<%= form.collection_select(:roaster_id, Roaster.all, :id, :roaster_name, :prompt => 'Select Roaster') %>
I've tried
<%= form.collection_select(:roaster_name, Roaster.all, :id, :roaster_name, :prompt => 'Select Roaster') %>
but this gives and undefined method error.
My roast_params
params.require(:roast).permit(:roaster, :roaster_id, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, countries_attributes: [:country_id, :country_name, regions_attributes: [:id, :region_name]])
Adding in :roaster_name doesn't solve either.
As requested full form:
<%= form_with(model: roast, local: true, multipart: true) do |form| %>
<% if roast.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger" role="alert">
<h2><%= pluralize(roast.errors.count, "error") %> prohibited this roast from being saved:</h2>
<ul>
<% roast.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
<form>
<div class="row">
<div class="col-6">
<div class="field form-group">
<%= form.label :roaster, class: 'control-label' %>
<%= form.collection_select(:roaster_id, Roaster.all, :id, :roaster_name, :prompt => 'Select Roaster') %>
</div>
</div>
<div class="col-6">
<div class="form-group">
<%= form.label :name, class: 'control-label' %>
<%= form.text_field :name, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<%= form.label :beans, "Blend", class: 'control-label' %><br />
<%= form.select :beans, [ 'Single Origin','Two Country Blend', 'Three Country Blend' ], :prompt => 'Select One', id: :roast_beans, class: "form-control" %>
</div>
<div class="row">
<%= form.fields_for :countries do |countries_form| %>
<div class="col-6">
<div class="form-group">
<%= countries_form.label :country %>
<%= countries_form.text_field :country_name, class: "form-control" %>
</div>
</div>
<div class="col-6">
<!-- note the appending of `countries_` to form.fields to allow for deeper nested to work-->
<%= countries_form.fields_for :regions do |regions_form| %>
<%= regions_form.label :region %>
<%= regions_form.text_field :region_name, class: "form-control" %>
<% end %>
<br />
</div>
<% end %>
</div>
<div class="form-group">
<%= form.label :bestfor, "Style", class: 'control-label' %><br />
<%= form.select :bestfor, [ 'Espresso','Filter' ], :prompt => 'Select One', id: :roast_bestfor, class: "form-control" %>
</div>
<div class="form-group">
<%= form.label :roast, "Strength", class: 'control-label' %><br />
<%= form.select :roast, [ 'Light','Medium','Dark' ], :prompt => 'Select One', id: :roast_roast, class: "form-control" %>
</div>
<div class="form-group">
<%= form.label :tastingnotes, "Tasting Notes (separate with commas, e.g chocolate, citrus)", class: 'control-label' %><br />
<%= form.text_area :tastingnotes, id: :roast_tastingnotes, class: "form-control" %>
</div>
<br />
<div class="form-group">
<%= form.label :avatar, "Upload image...", class: 'control-label' %>
<%= form.file_field :avatar %>
</div>
<div class="actions">
<%= form.submit class: "btn btn-success" %> <%= link_to "Cancel", "/roasts", class: "btn btn-secondary"%>
</div>
<% end %>
</form>
roast_controller.rb
class RoastsController < ApplicationController
before_action :set_roast, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:create, :edit, :update, :destroy]
before_action :set_search
# GET /roasts
# GET /roasts.json
def index
#q = Roast.ransack(params[:q])
#roastsalpha = #q.result.order(:name)
#roastcount = Roast.count(:country)
#roasts = Roast.order(:name).count
#countroastschart = Roast.order("roaster DESC").all
end
# GET /roasts/1
# GET /roasts/1.json
def show
#roast = Roast.friendly.find(params[:id])
#commentable = #roast
#comments = #commentable.comments
#comment = Comment.new
#sameroaster = Roast.where(roaster: #roast.roaster)
#samecountry = Roast.where(country: #roast.country)
#roastcount = Roast.where(roaster: #roast.roaster)
end
# GET /roasts/new
def new
#roast = Roast.new
3.times {#roast.countries.build.regions.build}
end
# GET /roasts/1/edit
def edit
3.times {#roast.countries.build.regions.build}
end
# POST /roasts
# POST /roasts.json
def create
#roast = Roast.new(roast_params)
respond_to do |format|
if #roast.save
format.html { redirect_to #roast, notice: 'Roast was successfully created.' }
format.json { render :show, status: :created, location: #roast }
else
format.html { render :new }
format.json { render json: #roast.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /roasts/1
# PATCH/PUT /roasts/1.json
def update
respond_to do |format|
if #roast.update(roast_params)
format.html { redirect_to #roast, notice: 'Roast was successfully updated.' }
format.json { render :show, status: :ok, location: #roast }
else
format.html { render :edit }
format.json { render json: #roast.errors, status: :unprocessable_entity }
end
end
end
# DELETE /roasts/1
# DELETE /roasts/1.json
def destroy
#roast.destroy
respond_to do |format|
format.html { redirect_to roasts_url, notice: 'Roast was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_roast
#roast = Roast.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def roast_params
params.require(:roast).permit(:roaster, :roaster_id, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, countries_attributes: [:country_id, :country_name, regions_attributes: [:id, :region_name]])
end
end
I think you are doing many wrong things. By looking your other questions I saw your models. I put some important things:
class Roast < ApplicationRecord
has_many :countries
accepts_nested_attributes_for :countries
end
class Country < ApplicationRecord
has_many :regions, inverse_of: :country
accepts_nested_attributes_for :regions
belongs_to :roast
end
class Region < ApplicationRecord
belongs_to :country, inverse_of: :regions
end
In these models I didn't see the Roaster. I assume a Roast belongs_to :roaster.
So: your Roast has many countries and each country has many regions. But you are passing country names and region names in your view to the create controller. You need to pass the ids, so that you save references to these models.
You have many unnecessary field in params, and some missing ones. This is how it should be:
def roaster_params
params.require(:roast).permit(:roaster_id, :name, :bestfor, :beans, :tastingnotes, :notes, :slug, :avatar, countries_attributes: [:id, regions_attributes: [:id]])
end
You don't need roast, roaster, country_name, region_name. You need the id of the country (and not the country_id), and the id of the region (and not the region_id)
In your form you should ask for country and region ids:
<%= countries_form.collection_select(:id, Country.all, :id, :name, :prompt => 'Select Country') %>
<%= regions_form.collection_select(:id, Region.all, :id, :name, :prompt => 'Select Region') %>
In fact this is more difficult, because a region belongs to a country, but here you are showing all regions. You should only show regions for the selected country (which is dynamic).

Rails join collection not recognizing parameters

I'm trying to create a record in a join table named Interventions. Basically in my application a user can do many interventions on an incident, and an incident can have interventions by many users. I pass the needed strong parameters, but the application gives the following errors when I try to save: "Incident must exist" and "User must exist". I spent hours on this, and can't figure out what is the problem. Can you please help me? I post the relevant code here:
user.rb (model)
has_many :interventions
has_many :incidents, through: :interventions
incident.rb (model)
has_many :interventions
has_many :users, through: :interventions
intervention.rb (model)
belongs_to :incident_priority
belongs_to :intervention_status
interventions_controller.rb
def new
#incident = Incident.find(params[:incident])
#user = User.find(current_user.id)
#intervention = Intervention.new(:user_id => #user, :incident_id => #incident)
#project = #incident.channel.project
#mirth = Mirth.find_by server_id: #incident.mirth_server_id
end
def create
#incident = Incident.find(params[:incident_id])
#user = User.find(params[:user_id])
#intervention = Intervention.create(intervention_params)
#project = #incident.channel.project
#mirth = Mirth.find_by server_id: #incident.mirth_server_id
respond_to do |format|
if #intervention.save
format.html { redirect_to new_intervention_path(#incident), notice: 'Intervention was successfully created.' }
format.json { render :show, status: :created, location: #intervention }
else
format.html { render :new, incident: :incident_id }
format.json { render json: #intervention.errors, status: :unprocessable_entity }
end
end
end
< .... >
def intervention_params
params.require(:intervention).permit(:user_id, :incident_id, :incident_priority_id, :begin_date, :end_date, :description,
:intervention_status_id, :forwarded_to)
end
In my view (interventions_form.html.erb):
<%= form_for(#intervention) do |f| %>
<% if #intervention.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#intervention.errors.count, "error") %> prohibited this intervention from being saved:</h2>
<ul>
<% #intervention.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group form-inline">
<%= hidden_field_tag :user_id, #user.id %>
<%= hidden_field_tag :incident_id, #incident.id %>
<strong>Interveniente:</strong>
<%= #user.first_name %> <%= #user.last_name %>
</div>
<div class="form-group form-inline">
<%= f.label 'Prioridade' %>
<%= f.collection_select :incident_priority_id, IncidentPriority.all, :id, :description, {}, {class: "form-control"} %>
</div>
<div class="form-group form-inline">
<%= f.label 'Data início intervenção' %>
<%= f.datetime_select :begin_date %>
</div>
<div class="form-group form-inline">
<%= f.label 'Data fim intervenção' %>
<%= f.datetime_select :end_date, :include_blank => true %>
</div>
<div class="form-group form-inline">
<%= f.label 'Observações' %>
<%= f.text_area :description %>
</div>
<div class="form-group form-inline">
<%= f.label 'Estado' %>
<%= f.collection_select :intervention_status_id, InterventionStatus.all, :id, :description, {}, {class: "form-control"} %>
</div>
<div class="form-group form-inline">
<%= f.label 'Encaminhado para:' %>
<%= f.text_area :forwarded_to %>
</div>
<div class="actions" align="right">
<%= link_to 'Voltar', incidents_path(:mirth => #mirth, :project => #project), class: "btn btn-info" %>
<%= f.submit "Gravar", class: "btn btn-info" %>
</div>
I run debug and the values in the hidden_field_tags are correctly filled. Also in the controller the #user and #incident are correctly populated, but #intervention has nil in the foreign keys :user_id and :incident_id.
Thanks in advance!
You need to associate the user and the incident with the intervention.
in your model...
class Intervention
belongs_to :user
belongs_to :incident
in your create method...
def create
#incident = Incident.find(params[:incident_id])
#user = User.find(params[:user_id])
#intervention = Intervention.create(intervention_params)
#intervention.incident = #incident
#intervention.user = #user
...
You need to change this:
def create
#incident = Incident.find(params[:incident_id])
#user = User.find(params[:user_id])
# ...
end
For this:
def create
#incident = Incident.find(params[:incident_id])
#user = User.find(params[:user_id])
intervention_params.merge(user_id: #user.id, incident_id: #incident.id)
# ...
end
And your model:
class Intervention
belongs_to :user
belongs_to :incident

Rails 4, Cocoon, ERB Template, how to make selected an options_from_collection_for_select in Edit Action?

This is my first time with Cocoon, and maybe this is a really dumb question, but I already spend many time looking how to do this with ERB template and avoid using simple_form or other helper.
Take a look of my models:
models/loot.rb
class Lot < ActiveRecord::Base
has_many :colindanciums, dependent: :destroy
has_many :cardinal_points, through: :colindanciums
accepts_nested_attributes_for :colindanciums, allow_destroy: true
end
models/colindancium.rb
class Colindancium < ActiveRecord::Base
belongs_to :cardinal_poing
belongs_to :lot
end
models/cardinal_point.rb
class CardinalPoint < ActiveRecord::Base
has_many :colindanciums
has_many :lots, through: :colindanciums
end
The form:
views/lots/_form.html.erb
<%= form_for(#lot, remote: true) do |f| %>
<%= render 'shared/error_messages', object: #lot %>
...
...
...
<fieldset id="colindancium-orientation">
<ol>
<%= f.fields_for :colindanciums do |colindancium| %>
<%= render 'colindancium_fields', f: colindancium %>
<% end %>
</ol>
<%= link_to_add_association 'Nueva Colindancia', f, :colindanciums, 'data-association-insertion-node' => "#colindancium-orientation ol", 'data-association-insertion-method' => "append" %>
</fieldset>
...
...
...
<% end %>
The partial:
views/lots/_colindancium_fields.html.erb
<li class="control-group nested-fields">
<div class="controls">
<%= f.label :description, "Descripcion:" %>
<%= f.text_field :description %>
<%= f.label :linear_meters, "Metros Lineales:" %>
<%= f.text_field :linear_meters %>
<%= f.label :cardinal_point_id, "Orientacion:" %>
<%= f.select :cardinal_point_id,
options_from_collection_for_select(CardinalPoint.all, :id, :name), { }, { :class => "form-control", :prompt => "Seleccione un Punto Cardinal" } %>
<%= link_to_remove_association "Eliminar", f %>
</div>
</li>
Everything works great when I insert new fields, it saves it in DB, it Update it in DB, my problem is in the options_from_collection_for_select when I open the form in Edit Action, the fourth parameter of this helper is the selected value... I can't find the way to make selected the value that is stored in my db, it always show the 1 index... I can't access the #... object from the _form, the other fields (:description, :linear_meters) are working quite good my problem is in the f.select, I don't know how to do it.
EDIT My controller:
# GET /lots/new
def new
#lot = Lot.new
#lot.colindanciums.build
authorize #lot
end
# PATCH/PUT /lots/1
# PATCH/PUT /lots/1.json
def update
authorize #lot
respond_to do |format|
if #lot.update(lot_params)
format.html { redirect_to #lot, notice: 'Lot was successfully updated.' }
format.json { render :show, status: :ok, location: #lot }
format.js
else
format.html { render :edit }
format.json { render json: #lot.errors, status: :unprocessable_entity }
format.js { render json: #lot.errors, status: :unprocessable_entity }
end
end
end
I change my logic in the select, i made it works in this way:
<div class="form-group">
<%= f.label :cardinal_point_id, "Orientacion:", :class => "control-label" %>
<%= f.select :cardinal_point_id , CardinalPoint.all.collect {|p| [ p.name, p.id ] }, { :include_blank => 'Seleccione un Punto Cardinal'}, :class => "form-control" %>
</div>
I post my answer in case anybody have the same issue.
You forgot to put the parenthesis correctly
<%= f.select (:cardinal_point_id,
options_from_collection_for_select(CardinalPoint.all, :id, :name), { }, { :class => "form-control", :prompt => "Seleccione un Punto Cardinal" }) %>

Pass multiple selected parameters to a submission link

I have a setup attempting to automate submission to a backend. There are 3 different dropdown boxes with user-selectable parameters. I set up my website like this (all 'scaffolds'):
class Xsearch < ActiveRecord::Base
has_many :xentry
has_many :spectrafile
has_many :parameter
end
Each entry/file/parameter has the belongs_to :xsearch in their model.
The index.html.erb of the xsearch has the following:
<h1>Spectra Submitter</h1>
<h2>Select a database to search</h2>
<%= collection_select("xpost", :id, Xentry.all(), :title, :name ) %>
<h2>Select a parameter file to use</h2>
<%= collection_select(:ppost, :id, Parameter.all(), :name, :name ) %>
<h2>Select a Spectra file (or folder) to search</h2>
<%= collection_select(:spost, :id, Spectrafile.all(), :name, :name ) %>
<%= link_to "Search", :controller => "xsearches", :action => "search" %>
I've tried using submit_tag as well. I have no idea how to trigger a method in my controller (if it should be in the controller? Since it's from the browser I assumed to put it here) that has the selected values from each collection_select.
So in short: How can I take the selected values for each collection_select and pass them to a function? Where should that function be placed (in the controller or in the .html.erb file)?
Thanks, this has been driving me crazy.
I ended up solving the issue by moving to a form_new method. Here's my code for anyone else who is searching. The purpose of this script was to allow other users to submit a search to a cluster through an authorized user.
<%= form_for(#xsearch) do |f| %>
<% if #xsearch.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#xsearch.errors.count, "error") %> prohibited this xsearch from being saved:</h2>
<ul>
<% #xsearch.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<h2>Pick A Database To Search</h2>
<%= collection_select(:db, :id, #all_entries, :id, :name) %>
<h2>Pick A Parameter File To Use</h2>
<%= collection_select(:para, :id, #all_parameters, :id, :name) %>
<h2>Pick a File or Folder To Search</h2>
<%= collection_select(:sfile, :id, #all_spectrafiles, :id, :name) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And the relevant bit in the controller's create: method
def create
#database = Xentry.find(params[:db][:id])
#paramfile = Parameter.find(params[:para][:id])
#spectrafile = Spectrafile.find(params[:sfile][:id])
#recurse = params[:recurse]
#email = params[:emailtag]
if #email.empty?
#email = "None"
end
if (#recurse == 'Yes')
#recurse = 1
else
#recurse = 0
end
#recurse = 0#disabled until kill methods are implemented
#hostname = hostname
#username = username
Net::SSH.start(#hostname, #username) do |session|
session.exec('source .bashrc')
session.exec('sh rscript.sh %s %s %s %s %d' % [#database['name'], #spectrafile['name'], #paramfile['name'], #email, #recurse])
#xsearch = Xsearch.new(:database => #database['name'], :parameters => #paramfile['name'], :spectra => #spectrafile['name'])
respond_to do |format|
if #xsearch.save
format.html { redirect_to #xsearch, notice: 'Search was successfully created.' }
format.json { render json: #xsearch, status: :created, location: #xsearch }
else
format.html { render action: "new" }
format.json { render json: #xsearch.errors, status: :unprocessable_entity }
end
end
end
end

Ruby on Rails dropdown values not saving

I'm new to RoR and having an issue when trying to save from multiple dropdowns. I have three objects - books, genres, and authors. A book object has a genre and author associated to it, but the issue is I can only manage to save either a genre or author to my book object, and not both. Here's where I'm at:
class Author < ActiveRecord::Base
validates :name, :presence => true
validates :biography, :presence => true
has_many :books
end
class Genre < ActiveRecord::Base
validates :description, :presence => true
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :genre
belongs_to :author
has_many :cartitems
validates :name, :presence => true
validates :price, :presence => true
validates :description, :presence => true
end
Controller:
def create
##book = Book.new(params[:book])
#author = Author.find(params[:author].values[0])
#genre = Genre.find(params[:genre].values[0])
#book = #author.books.create(params[:book])
#one or the other saves, but not both
##book = #genre.books.create(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
Not sure if this will help out or not, but here's what the dropdowns look like in the View:
<div class="field">
<%= f.label :genre %><br />
<%= #items = Genre.find(:all)
select("genre", "description", #items.map {|u| [u.description,u.id]}, {:include_blank => true})%>
Appreciate any help with this.
EDIT - Here's my full form.
<%= form_for(#book) do |f| %>
<% if #book.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#book.errors.count, "error") %> prohibited this book from being saved:</h2>
<ul>
<% #book.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 :price %><br />
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :genre %><br />
<%= #items = Genre.find(:all)
select("genre", "description", #items.map {|u| [u.description,u.id]}, {:include_blank => true})%>
</div>
<div class="field">
<%= f.label :author %><br />
<%=#items = Author.find(:all)
select("author", "name", #items.map {|u| [u.name,u.id]}, {:include_blank => true}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Update your select fields to be defined like this:
<div class="field">
<%= f.label :genre %><br />
<%= f.select( :genre_id, Genre.all.map {|u| [u.description,u.id]}, {:include_blank => true}) %>
</div>
<div class="field">
<%= f.label :author %><br />
<%= f.select( :author_id, Author.all.map {|u| [u.name,u.id]}, {:include_blank => true}) %>
</div>
And your controller action should be like this:
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
Also, remove the format.xml calls if you don't need them, they're just cluttering your controller action.
There are lots of different ways to fix your problem, it would help to see exactly what's in your params hash and what your full form looks like, but no matter. Here is one way:
#book = #author.books.create(:genre => #genre)
Here is another (essentially the same thing):
#book = #author.books.create {|book| book.genre = #genre}
You could also instantiate the book separately:
#author = Author.find(params[:author].values[0])
#genre = Genre.find(params[:genre].values[0])
#book = Book.create(:author => #author, :genre => #genre)
My guess is you didn't quite build your form correctly, otherwise your params hash would look similar to this {:book => {:author => 1, :genre => 5}} and you would be able to do this:
#book = Book.create(params[:book])
And you would not look up the author using params[:author], but would instead do params[:book][:author] if you needed to do it at all.

Resources