Can't mass-assign protected attributes: stripe_card_token - ruby-on-rails

I'm trying to create a charge with stripe. I get the following error when attempting to create order object, but I have set attr_accessor :stripe_card_token. Does anyone know what I am doing wrong?
ActiveModel::MassAssignmentSecurity::Error in OrdersController#create
Can't mass-assign protected attributes: stripe_card_token
OrdersController - Create action
def create
#order = current_cart.build_order(params[:order])
#order.ip_address = request.remote_ip
#order.user_id = current_user.id
respond_to do |format|
if #order.save_with_payment
#order.add_line_items_from_cart(current_cart)
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
format.html { render :action => "success", :notice => 'Thank you for your order.' }
format.xml { render :xml => #order, :status => :created, :location => #order }
else
format.html { render :action => "new" }
format.xml { render :xml => #order.errors,
:status => :unprocessable_entity }
end
end
end
OrderModel
class Order < ActiveRecord::Base
# PAYMENT_TYPES = [ "visa", "master card", "Amex", "Discover" ] Controll the payment options via Model
attr_accessible :first_name, :last_name, :ip_address, :cart_id, :house_id
attr_accessor :stripe_card_token
belongs_to :user
belongs_to :house
belongs_to :cart
has_many :transactions, :class_name => "OrderTransaction"
has_many :line_items, :dependent => :destroy
validates :house_id, presence: true
validates :cart_id, presence: true
def price_in_cents
(cart.total_price*100).round
end
def add_line_items_from_cart(cart)
cart.line_items.each do |item|
item.cart_id = nil
line_items << item
end
end
def save_with_payment
if valid?
Stripe::Charge.create(amount: price_in_cents, currency: "cad", description: current_user.name, card: stripe_card_token)
# self.stripe_order_token = order.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
OrderView _Form
<%= f.error_notification %>
<%= f.error_messages %>
<%= f.hidden_field :stripe_card_token %>
<%= f.hidden_field :cart_id%>
<div class="form-inputs">
<p><%#if user does not have a house Make a page (please order a home valuation first) %></p>
<div class="contain">
<h3>Select House</h3>
<%= f.input :house_id, :as => :radio_buttons, :collection => current_user.houses.all.map{|h| [h.address, h.id]}%>
</div>
<%= f.input :first_name %>
<%= f.input :last_name %>
<div class="field">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_code, "Security Code on Card (CVV)" %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
</div>
</div>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
Orders.js.coffee
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
order.setupForm()
order =
setupForm: ->
$('#new_order').submit ->
$('input[type=submit]').attr('disabled', true)
if $('#card_number').length
order.processCard()
false
else
true
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, order.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#order_stripe_card_token').val(response.id)
$('#new_order')[0].submit()
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)

You still need to include :stripe_card_token under attr_accessible in your model

Active record (the layer in your rails stack that provides an interface between your ruby code and your database) protects your database from unwanted end-user assignment using the attr_accessible method. if present in your model it makes sure that a request can't write to your database unless the attribute is listed.
You've got attr_accessible here but don't have :stripe_card_token listed, so you can't save to that field.
attr_accessible :first_name, :last_name, :ip_address, :cart_id, :house_id add , :stripe_card_token
You may have though the attr_accessor :stripe_card_token line would somehow be related, but that just sets the getter and setter methods for the attribute.
The difference is better laid out here
In this question

You can read more about mass-assignment here: http://www.h-online.com/security/news/item/Rails-3-2-3-makes-mass-assignment-change-1498547.html

Related

Rails nested form Unpermitted parameter

When i create or edit product, my merchant_product_detail will not be created or edit due to
Unpermitted parameter: merchant_id. But other like id and price are able to pass strong parameters, only merchant_id could not pass it. Kindly help me why my merchant_id is not permit in this case?
params return in binding.pry mode
"product"=>
{"name"=>"fewrgvers",
"description"=>"",
"product_categories_attributes"=>{"0"=>{"id"=>""}},
"merchant_product_details_attributes"=>
{"0"=>{"merchant_id"=>["2"], "id"=>"", "price"=>"123"}}
"
product_params return
Unpermitted parameter: merchant_id
=> {"name"=>"fewrgvers",
"description"=>"",
"merchant_product_details_attributes"=>{"0"=>{"id"=>"", "price"=>""}}
product.rb
has_many :merchant_product_details
accepts_nested_attributes_for :merchant_product_details, reject_if: proc { |attributes| attributes['merchant_id'].blank? }
has_many :merchants, through: :merchant_product_details
merchant.rb
has_many :merchant_product_details
has_many :products, through: :merchant_product_details
accepts_nested_attributes_for :merchant_product_details
merchant_product_detail.rb
belongs_to :product
belongs_to :merchant
product_controller.rb
def new
#product = Product.new
#product.merchant_product_details.build
end
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to root_path, notice: 'Product was successfully created.' }
else
format.html { render :new }
end
end
end
end
def update
respond_to do |format|
if #product.update_attributes(product_params)
format.html { redirect_to root_path, notice: 'Product was successfully updated.' }
else
format.html { render :edit }
end
end
end
params.require(:product).permit(:name, :description,
merchant_product_details_attributes: [:id, :merchant_id, :price]
_form.html.erb
<%= form_for(#product, :url => path, html: { class: "form-horizontal", role: "form" }) do |f| %>
<%= f.fields_for :merchant_product_details do |builder| %>
<div class="form-group row">
<%= builder.label :merchant_id, class: "col-md-2 control-label" %>
<div class="col-md-8">
<%= builder.select :merchant_id, Merchant.all.collect {|x| [x.name, x.id]}, {include_hidden: false} ,prompt: "Select something", multiple: true, class: "select2" %>
<%= builder.hidden_field :id %><br>
<%= builder.label :price %>
<%= builder.number_field :price %>
</div>
<% end %>
The problem is the multiple: true in the form field for merchant_id. This means that the param will be an array, as it could be multiple merchant ids.
If this is what you want then I would recommend changing the name to merchant_ids and allow an array like this:
params.require(:product).permit(:name, :description,
merchant_product_details_attributes: [:id, :price, merchant_ids: []])
Having a look at your model relations I think you only want to have one id though, in which case it should be enough to remove the multiple: true in the select.
<%= builder.select :merchant_id, Merchant.all.collect {|x| [x.name, x.id]}, {include_hidden: false}, prompt: "Select something", class: "select2" %>

Unable to charge customer using stripe

I'm trying to save a customer with credit card details and charge it later.
So far I was able to do the following:
Get the card token to Stripe (I see it in the logs in stripe and in my Rails console)
Create a customer, send it to Stripe and save the customer id in my database.
When I try to charge the customer I get the following error:
Stripe::CardError (Cannot charge a customer that has no active card)
Maybe the card token is not assigned to the customer properly? How can I solve it? maybe it's something simple that I'm missing but I've been trying to get a solution for a while.
application.rb:
class Application < ActiveRecord::Base
attr_accessor :stripe_card_token
def save_with_payment
if valid?
customer = Stripe::Customer.create(
description: id,
email: self.user.email,
source: self.stripe_card_token
)
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
applications.js.coffee:
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
application.setupForm()
application =
setupForm: ->
$('#new_application').submit ->
$('input[type=submit]').attr('disabled', true)
if $('#card_number').length
application.processCard()
false
else
true
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
exp_month: $('#card_month').val()
exp_year: $('#card_year').val()
Stripe.createToken(card, application.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#application_stripe_card_token').val(response.id)
$('#new_application')[0].submit() ->
return true if($form.find('.application_stripe_card_token').val())
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
applications_controller.rb
class ApplicationsController < ApplicationController
before_action :set_application, only: [:show, :edit, :update, :confirmation, :charge]
after_action :charge, only: [:create]
def new
#listing = Listing.find(params[:listing_id])
#application = Application.new
if Guarantor.where(application_id: #application.id).first.blank?
#guarantor = Guarantor.new(params[:guarantor])
end
end
def create
#listing = Listing.find(params[:listing_id])
#application = current_user.applications.create(application_params)
if params[:btnSubmit]
redirect_to confirmation_listing_application_path(#application.listing_id, #application.id)
elsif #application.save_with_payment
if params[:application][:roommates_attributes].present?
params[:application][:roommates_attributes].values.each do |a|
#email = a[:email]
end
#user = User.where(email: #email).first
if #user.blank?
flash[:error] = "The email address doesn't exist in our records"
redirect_to new_listing_application_path(#application.listing_id)
#application.destroy
else
redirect_to confirmation_listing_application_path(#application.listing_id, #application.id), :notice => "Thank you for applying!"
end
else
redirect_to confirmation_listing_application_path(#application.listing_id, #application.id), :notice => "Thank you for applying!"
end
end
end
def charge
Stripe::Charge.create(
:amount => 1500,
:currency => "usd",
:customer => #application.stripe_customer_token
)
end
private
def set_application
#application = Application.find(params[:id])
end
def application_params
params.require(:application).permit(
:_destroy,
:user_id,
:listing_id,
:stripe_customer_token,
:st_address,
:unit,
:city,
:state
)
end
end
form.html.erb
<%= form_for [#listing, #application], html: {id: "new_application", multipart: true} do |f| %>
<%= f.hidden_field :stripe_card_token %>
<% if #application.stripe_customer_token.present? %>
Credit Card has been provided.
<% else %>
<div class="row">
<div class="col-md-6">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil, "data-stripe" => "number" %>
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= label_tag :card_code, "Security Code (CVC)" %>
<%= text_field_tag :card_code, nil, name: nil, "data-stripe" => "cvc" %>
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month", "data-stripe" => "exp-month" } %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year", "data-stripe" => "exp-year"} %>
</div>
</div>
<% end %>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
<div class="nextBackBtns">
<a herf="#" class="btn btn-primary-custom btnBack" data-content="details">Back</a>
<%= f.submit "Save", class: "btn btn-primary" %>
</div>
<% end %>
Your application_params() filter method doesn't appear to permit the stripe_card_token that gets submitted from your form. I believe that if you add that to your permit() filter list, you should be able to get the value through to the controller, so that it can be used when it's needed.

Save successful on nested attributes on has many through but doesn't add to database

I and order and item system with Rails 4 with a has many through association. When I select create order the webpage says that the order was created successfully however the link is not made in the OrderItems linking tables meaning that the items relating to that order do not appear on the show page or edit page for an order.
The order is also linked to an employee. The current employee ID is linked to that order. I have just not been able to figure out how to add each item to the database.
p.s. I am using a gem called nested_form to handle all of the jQuery on the front end of dynamically adding and removing new items on the _form.html.erb for Orders.
orders_controller.rb
class OrdersController < ApplicationController
before_action :logged_in_employee, only:[:new, :show, :create, :edit, :update, :index]
before_action :admin_employee, only:[:destroy]
before_action :set_order, only: [:show, :edit, :update, :destroy]
def new
#order = Order.new
#items = Item.all
end
def edit
#items = Item.all
end
def create
#order = current_employee.orders.build(order_params)
if #order.save
flash[:success] = "Order successfully created"
redirect_to #order
else
render 'new'
end
end
def update
if #order.update_attributes(order_params)
flash[:success] = "Order updated!"
redirect_to current_employee
else
render 'edit'
end
end
....
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:table_number, :number_of_customers, :status, :comment, order_items_attributes: [:id, :order_id, :item_id, :_destroy])
end
end
order.rb
class Order < ActiveRecord::Base
belongs_to :employee
has_many :order_items
has_many :items, :through => :order_items
default_scope { order('status DESC') }
validates :employee_id, presence: true
validates :table_number, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 20 }, presence: true
validates :number_of_customers, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 50 }, presence: true
validates :status, inclusion: { in: %w(Waiting Ready Closed), message: "%{value} is not a status" }
accepts_nested_attributes_for :order_items, :reject_if => lambda { |a| a[:item_id].blank? }
end
item.rb
class Item < ActiveRecord::Base
belongs_to :menu
has_many :order_items
has_many :orders, :through => :order_items
before_save { name.capitalize! }
VALID_PRICE_REGEX = /\A\d+(?:\.\d{0,2})?\z/
validates :name, presence: true, length: { maximum: 100 }
validates :price, format: { with: VALID_PRICE_REGEX }, numericality: { greater_than: 0, less_than_or_equal_to: 100}, presence: true
validates :course, inclusion: { in: %w(Starter Main Dessert Drink), message: "%{value} is not a course" }
validates :menu_id, presence: true
end
order_item.rb
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
validates :order_id, presence: true
validates :item_id, presence: true
end
orders/_form.html.erb
<% provide(:title, "#{header(#order)} #{#order.new_record? ? "order" : #order.id}") %>
<%= link_to "<< Back", :back, data: { confirm: back_message } %>
<h1><%= header(#order) %> <%= #order.new_record? ? "order" : #order.id %></h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= nested_form_for #order do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="row">
<div class="col-xs-6">
<%= f.label :table_number %>
<%= f.number_field :table_number, class: 'form-control' %>
</div>
<div class="col-xs-6">
<%= f.label :number_of_customers %>
<%= f.number_field :number_of_customers, class: 'form-control' %>
</div>
</div>
<%= f.fields_for :order_items do |oi| %>
<%= oi.grouped_collection_select :item_id, Menu.where(active: true).order(:name), :items, :name, :id, :name, { include_blank: 'Select Item' }, class: 'items_dropdown' %>
<%= oi.hidden_field :item_id %>
<%= oi.hidden_field :order_id %>
<%= oi.link_to_remove "Remove item" %>
<% end %>
<p><%= f.link_to_add "Add an item", :order_items %></p>
<br>
<% if !#order.new_record? %>
<%= f.label "Status" %>
<%= f.select(:status, options_for_select([['Waiting', 'Waiting'], ['Ready', 'Ready'], ['Closed', 'Closed']], #order.status), class: 'form-control') %>
<% end %>
<%= f.label "Comments - how would you like your steak cooked? Or feedback" %>
<%= f.text_area :comment, size: "20x5", class: 'form-control' %>
<%= f.submit submit_label(#order), class: "btn btn-success col-md-6" %>
<% end %>
<% if !#order.new_record? && current_employee.try(:admin?) %>
<%= link_to "Cancel", :back, data: { confirm: back_message }, class: "btn btn-warning col-md-offset-1 col-md-2" %>
<%= link_to "Delete", #order, method: :delete, data: { confirm: "Are you sure? The employee will be deleted! "}, class: "btn btn-danger col-md-offset-1 col-md-2" %>
<% else %>
<%= link_to "Cancel", :back, data: { confirm: back_message }, class: "btn btn-warning col-md-offset-1 col-md-5" %>
<% end %>
</div>
</div>
Issue: Let's say your order has got many items and you want the items to be saved just when the order is created.
order = Order.new(order_params)
item = Item.new(name: 'item-name', product_info: 'etc etc')
if order.save
item.create
order.items << item
end
You need to follow similar approach in your case. just get the item_params properly and apply above rule.
Try below approach, hope that helps. :)
def create
#order = current_employee.orders.build(order_params)
if #order.save
item = params["order"]["order_items_attributes"]
#please debug above one and try to get your items from params.
order_item = Item.create(item)
#makes sure above item hold all item attributes then create them first
#order.items << item
redirect_to #order
end
end

Subscription not creating on custom Stripe form but is creating subscription on Stripe

Currently my code is not creating an actual subscription item in the DB however it is creating the subscription on Stripe.
I've checked the logs and I can't see any item create being called when the subscription form is completed. I played around and changed the Stripe code from before_create to after_create and that seemed to work, however that is pointless as we can only give the user a subscription if they have subscribed through Stripe.
Any ideas? Thanks!
subscriptions_controller.rb
class SubscriptionsController < ApplicationController
before_filter :authenticate_user!
def new
#subscription = Subscription.new
end
def create
#subscription = Subscription.new(params[:subscription])
if #subscription.save_with_payment
redirect_to #subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
def show
#subscription = Subscription.find(params[:id])
end
def subscription_params
params.require(:subscription).permit(:stripe_card_token)
end
end
subscription.rb
class Subscription < ActiveRecord::Base
belongs_to :user
attr_accessor :stripe_card_token
before_create :save_with_payment
def save_with_payment
customer = Stripe::Customer.create(
:card => stripe_card_token,
:description => "name",
:plan => 121,
:email => "email")
self.stripe_customer_id = customer.id
self.plan = 121
end
end
subscriptions.js.coffee
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
subscription.setupForm()
subscription =
setupForm: ->
$('#new_subscription').submit (e) ->
$('input[type=submit]').attr('disabled', true)
subscription.processCard()
return false
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, subscription.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#subscription_stripe_card_token').val(response.id)
$('#new_subscription')[0].submit()
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
false
new.html.erb
<div class='panel panel-default'>
<div class='panel-heading'>
<h2>Subscribe</h2>
</div>
<div class='panel-body'>
<%= form_for #subscription, :html => {:class => 'main-form'} do |f| %>
<%= f.hidden_field :stripe_card_token %>
<div id='stripe_error' class="alert alert-info" style='display:none'>
</div>
<span class="help-block">Nothing is billed to your card for 7 days. <b>Guaranteed. </b>
<br>If you choose to continue after 7 days, only then will you be billed.</span>
<div class='form-group'>
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil, class: 'form-control input-box', :placeholder => 'Credit Card Number' %>
</div>
<div class='row'>
<div class="col-xs-6">
<%= label_tag :card_code, "Security Code on Card (CVC)" %>
<%= text_field_tag :card_code, nil, name: nil, class: 'form-control input-box', :placeholder => 'Security Code on Card (CVC)' %>
</div>
<div class="col-xs-6">
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year+1, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
</div>
</div>
<div>
<%= f.submit "Subscribe", class: 'btn standard-button' %>
</div>
<% end %>
</div>
</div>
I was able to resolve this by removing the following:
before_create :save_with_payment

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