Rails app: Allow people to make a purchase without logging in - ruby-on-rails

Im trying to remove the signing up / logging in requirement on my rails app for users to make a booking but failed to do so. I'm pretty new and I'm not sure what other changes I'm suppose to make but missed out, any help will be appreciated, thanks!
Working code (with the signing up / logging in requirement)
class CourseController < ApplicationController
before_filter { #account_menu = :courses }
before_filter :authenticate_user!, :except => ['show', 'find', 'messages', 'chat_threads', 'new']
before_filter lambda {
if current_profile.try(:learner?)
flash[:alert] = "You cannot access these pages"
redirect_to '/'
end
}, :only => [:new, :edit, :cancel, :start, :complete]
before_filter lambda {
if current_profile.teacher?
flash[:alert] = "You cannot access these pages"
redirect_to '/'
end
}, :only => [:book, :wish_list, :wish, :unwish, :cancel_booking, :pending]
layout 'account'
def book
#title = "Book a Course"
#course = Course.by_uid(params[:uid])
if current_profile.learner?
if request.post?
price = params[:price].try(:to_f) || 0
current_profile.update_attributes({ :contact_email => params[:contact_email], :contact_phone => params[:contact_phone] })
params['payment-option'] = 'learnlist' if price == 0
case params['payment-option']
when 'learnlist' then
if current_user.balance >= price
current_user.transaction do
br = BookingRequest.create!({
:course_id => #course.id,
:deposited_price => price,
:hourly_price => params[:hourly_price].try(&:to_f),
:lessons => params[:lessons] || [],
:end_of_base_period => params[:end_of_base_period],
:learner_id => current_profile.id,
:source => 'learnlist',
:comments_by_learner => params[:comments],
:place_to_come_by_learner => params[:place_to_come],
:attendance => params[:attendance],
:learner_username => params[:username],
:learner_video_chat_platform => params[:video_chat_platform],
:cancellation_commission => #course.cancellation_commission
})
flash[:notice] = "Your booking request has been successfully sent to the teacher for confirmation"
Notification.add(#course.teacher.user, 'booking_request', br)
redirect_to course_path(#course.uid)
end
else
flash.now[:alert] = "You don't have enough funds in your account to book this course. You'll have to pay with PayPal to book the class"
end
when 'paypal' then
if !current_profile.paypal_set_up? || params[:paypal_email] != current_profile.paypal_email
result = Financials.paypal_preapproval(current_profile, params[:paypal_email], { :course => #course.uid, :price => price, :lessons => params[:lessons] || [], :end_of_base_period => params[:end_of_base_period], :hourly_price => params[:hourly_price].try(&:to_f) })
if result
current_profile.update_attributes!({
:paypal_preapproval_id => result[:preapproval_id],
:paypal_preapproval_confirmed_at => nil,
:paypal_email => params[:paypal_email]
})
redirect_to result[:redirect_url]
else
flash.now[:alert] = "Could not setup PayPal payments. Payments preapproval could not be requested"
end
else
br = BookingRequest.create!({
:course_id => #course.id,
:deposited_price => price,
:hourly_price => params[:hourly_price].try(&:to_f),
:lessons => params[:lessons] || [],
:end_of_base_period => params[:end_of_base_period],
:learner_id => current_profile.id,
:source => 'paypal',
:comments_by_learner => params[:comments],
:place_to_come_by_learner => params[:place_to_come],
:attendance => params[:attendance],
:learner_username => params[:username],
:learner_video_chat_platform => params[:video_chat_platform],
:cancellation_commission => #course.cancellation_commission,
:learnlist_partial_funding => params[:learnlist_partial].try(:to_i) == 1
})
Notification.add(#course.teacher.user, 'booking_request', br)
flash[:notice] = "Booking successfully submitted"
redirect_to course_path(#course.uid)
end
when 'braintree' then
if params[:payment_method_nonce].blank?
flash.now[:alert] = 'You did not configure your payment method. Please click Configure and set it up to proceed'
else
br = BookingRequest.create!({
:course_id => #course.id,
:deposited_price => price,
:hourly_price => params[:hourly_price].try(&:to_f),
:lessons => params[:lessons] || [],
:end_of_base_period => params[:end_of_base_period],
:learner_id => current_profile.id,
:source => 'braintree',
:comments_by_learner => params[:comments],
:place_to_come_by_learner => params[:place_to_come],
:attendance => params[:attendance],
:learner_username => params[:username],
:learner_video_chat_platform => params[:video_chat_platform],
:braintree_payment_method_nonce => params[:payment_method_nonce],
:cancellation_commission => #course.cancellation_commission,
:learnlist_partial_funding => params[:learnlist_partial].try(:to_i) == 1
})
Notification.add(#course.teacher.user, 'booking_request', br)
flash[:notice] = "Booking successfully submitted"
redirect_to course_path(#course.uid)
end
end
end
else
flash[:alert] = "You cannot access this view"
redirect_to '/'
end
end
My attempts to remove the signing up / logging in requirement are as follow. I failed to do it as clicking the book button brings me back to the homepage instead of the book view.
class CourseController < ApplicationController
before_filter { #account_menu = :courses }
before_filter :authenticate_user!, :except => ['show', 'find', 'messages', 'chat_threads', 'new', 'book']
before_filter lambda {
if current_profile.try(:learner?)
flash[:alert] = "You cannot access these pages"
redirect_to '/'
end
}, :only => [:new, :edit, :cancel, :start, :complete]
before_filter lambda {
if current_profile.try(:teacher?)
flash[:alert] = "You cannot access these pages"
redirect_to '/'
end
}, :only => [:book, :wish_list, :wish, :unwish, :cancel_booking, :pending]
layout 'account'
def book
#title = "Book a Course"
#course = Course.by_uid(params[:uid])
if request.post?
price = params[:price].try(:to_f) || 0
current_profile.update_attributes({ :contact_email => params[:contact_email], :contact_phone => params[:contact_phone] })
params['payment-option'] = 'learnlist' if price == 0
case params['payment-option']
when 'learnlist' then
if current_user.balance >= price
current_user.transaction do
br = BookingRequest.create!({
:course_id => #course.id,
:deposited_price => price,
:hourly_price => params[:hourly_price].try(&:to_f),
:lessons => params[:lessons] || [],
:end_of_base_period => params[:end_of_base_period],
:learner_id => current_profile.id,
:source => 'learnlist',
:comments_by_learner => params[:comments],
:place_to_come_by_learner => params[:place_to_come],
:attendance => params[:attendance],
:learner_username => params[:username],
:learner_video_chat_platform => params[:video_chat_platform],
:cancellation_commission => #course.cancellation_commission
})
flash[:notice] = "Your booking request has been successfully sent to the teacher for confirmation"
Notification.add(#course.teacher.user, 'booking_request', br)
redirect_to course_path(#course.uid)
end
else
flash.now[:alert] = "You don't have enough funds in your account to book this course. You'll have to pay with PayPal to book the class"
end
when 'paypal' then
if !current_profile.paypal_set_up? || params[:paypal_email] != current_profile.paypal_email
result = Financials.paypal_preapproval(current_profile, params[:paypal_email], { :course => #course.uid, :price => price, :lessons => params[:lessons] || [], :end_of_base_period => params[:end_of_base_period], :hourly_price => params[:hourly_price].try(&:to_f) })
if result
current_profile.update_attributes!({
:paypal_preapproval_id => result[:preapproval_id],
:paypal_preapproval_confirmed_at => nil,
:paypal_email => params[:paypal_email]
})
redirect_to result[:redirect_url]
else
flash.now[:alert] = "Could not setup PayPal payments. Payments preapproval could not be requested"
end
else
br = BookingRequest.create!({
:course_id => #course.id,
:deposited_price => price,
:hourly_price => params[:hourly_price].try(&:to_f),
:lessons => params[:lessons] || [],
:end_of_base_period => params[:end_of_base_period],
:learner_id => current_profile.id,
:source => 'paypal',
:comments_by_learner => params[:comments],
:place_to_come_by_learner => params[:place_to_come],
:attendance => params[:attendance],
:learner_username => params[:username],
:learner_video_chat_platform => params[:video_chat_platform],
:cancellation_commission => #course.cancellation_commission,
:learnlist_partial_funding => params[:learnlist_partial].try(:to_i) == 1
})
Notification.add(#course.teacher.user, 'booking_request', br)
flash[:notice] = "Booking successfully submitted"
redirect_to course_path(#course.uid)
end
when 'braintree' then
if params[:payment_method_nonce].blank?
flash.now[:alert] = 'You did not configure your payment method. Please click Configure and set it up to proceed'
else
br = BookingRequest.create!({
:course_id => #course.id,
:deposited_price => price,
:hourly_price => params[:hourly_price].try(&:to_f),
:lessons => params[:lessons] || [],
:end_of_base_period => params[:end_of_base_period],
:learner_id => current_profile.id,
:source => 'braintree',
:comments_by_learner => params[:comments],
:place_to_come_by_learner => params[:place_to_come],
:attendance => params[:attendance],
:learner_username => params[:username],
:learner_video_chat_platform => params[:video_chat_platform],
:braintree_payment_method_nonce => params[:payment_method_nonce],
:cancellation_commission => #course.cancellation_commission,
:learnlist_partial_funding => params[:learnlist_partial].try(:to_i) == 1
})
Notification.add(#course.teacher.user, 'booking_request', br)
flash[:notice] = "Booking successfully submitted"
redirect_to course_path(#course.uid)
end
end
end
else
flash[:alert] = "You cannot access this view"
redirect_to '/'
end
Sorry for the long block of code, if there's a need for any more information, I'll be happy to refurnish.

The standard way of dealing with this is to create a user account for the user, without any personal details, but keeping them "logged in" to this user account. This way they can have persistence across pages, can fill their basket, come back later on the same computer etc.
Later, when you actually need their personal details you can say "Before we go to the next step you need to register". Then, you can add the personal details to that account you created for them earlier, and do email verification or whatever you want to do.
With this approach, you will end up with lots of "incomplete" user accounts, where the person never bothered to register, and you could have a scheduled task to delete all the ones that are more than a week old, for example.

Related

undefined method `[]' for false:FalseClass on adaptivepayments-sdk-ruby

Someone is having this issue? or now why this is happing on configuring the paypal sdk adaptive?
place the configuration on the yml did not show this message but did not work either, so
i place the sdk configure on: buy action
and on the log shows:
line 58 is PayPal::SDK.configure
NoMethodError (undefined method []' for false:FalseClass):
app/controllers/orders_controller.rb:58:inbuy'
def buy
require 'paypal-sdk-adaptivepayments'
PayPal::SDK.configure(
:mode => "live", # Set "live" for production
:app_id => "APP-xxxxx",
:username => "xxxx.yyyy.com",
:password => "xxxx",
:signature => "xxxxx" )
#api = PayPal::SDK::AdaptivePayments.new
order = Order.find(params[:id])
#pay = #api.build_pay({
:actionType => "PAY",
:cancelUrl => carts_url,
:currencyCode => "US",
:feesPayer => "SENDER",
:ipnNotificationUrl => ipn_notification_order_url(order),
:receiverList => {
:receiver => [{
:email => seller#seller.com,
:amount => 1.0,
:primary => true},
{:email => buyer#buyer.com,
:amount => 1.0,
:primary => false}]},
:returnUrl => carts_url })
#response = #api.pay(#pay)
# Access response
if #response.success? && #response.payment_exec_status != "ERROR"
#response.payKey
redirect_to #api.payment_url(#response) # Url to complete payment
else
#response.error[0].message
redirect_to fail_order_path(order)
end
end

how to do ccavenuee payment gateway integration in rails

I tried ccavenue but I'am getting this error. paypal is working fine.
undefined methodpayment_service_for'`
This is my controller action
def create
#subscription = Subscription.new(subscription_params)
#programme = Programme.find(subscription_params[:programme_id])
rand_number = rand.to_s[2..11]
#programme.update_attributes(:invoice_id => rand_number)
session[:programme_id]=#programme.id
session[:invoice_id]=#programme.invoice_id
#paypal = PaypalPayment.create(:material_type => 'Programmes',:invoice_id => rand_number,:currency => #programme.currency, :status => 'Processing', :created_at => DateTime.now, :user_id => current_user.specific.id, :email_id => current_user.specific.email, :programme_id => #programme.id,:amount => #programme.price_paisas)
#paypal.save
`session[:paypal_id]=#paypal.id
logger.info #programme.inspect
if subscription_params[:payment_type] == 'paypal'
item_details=[]
if #programme.currency == 'INR'
price = #programme.price.exchange_to('USD')
else
price = #programme.price
end
logger.info price.inspect
item_details << {:name => #programme.title, :quantity => '1', :amount => price.fractional}
response = EXPRESS_GATEWAY.setup_purchase(price.fractional,
:items => item_details,
:currency => "USD",
:order_id => #programme.invoice_id,
:return_url => students_success_url,
:cancel_return_url => students_root_url
)
logger.info response.inspect
session[:programme_price]=price
return redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
elsif subscription_params[:payment_type] == 'ccavenue'
payment_service_for #programme.invoice_id, CCAVENUE_ACCOUNT,
:amount => #programme.price.fractional,
:currency => 'INR',
:service => :ccavenue do |service|
service.customer :name => current_user.name,
:email => current_user.email,
:phone => current_user.mobile
service.redirect :return_url => students_success_url
submit_tag 'Proceed to payment'
end
end
end
end`
I referred this link:
https://github.com/meshbrain/active_merchant_ccavenue
The payment_service_for is the view helper of the Active Merchant gem. You should use this method inside views or you should include view helpers inside your controller.

How to display Order id in paypal transaction detail page?

we are using rails4 , activemerchant 1.47.0 .
Normally, order id is not showing in transaction detail page for a transaction of a order in paypal.
How can we set the order id in transaction detail page of a paypal transaction ?
These are the methods used for a transaction and purchase.
response = ACTIVE_GATEWAY.setup_purchase((payment.amount * 100),
ip: request.remote_ip,
return_url: "url",
cancel_return_url: url,
currency: "USD",
items: [{name: order.number, description: "Order description", quantity: "1", amount: (payment.amount * 100)}]
)
redirect_to ACTIVE_GATEWAY.redirect_url_for(response.token)
Purchase
purchase_response = ACTIVE_GATEWAY.purchase((payment.amount* 100), {
:ip => request.remote_ip,
:token => token,
:payer_id => payerID
})
Thanks
Please try like this.
This is for development environment.
config/development.rb
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :test
paypal_options = {
:login => "email_id",
:password => "password",
:signature => "signature"
}
::EXPRESS_GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
end
Controller::
def express_paypal
order = current_user.orders.find(params[:id])
amount = order.total_amount
response = EXPRESS_GATEWAY.setup_purchase(amount,
:ip => request.remote_ip,
:return_url => url_for(:action => 'complete', :id => order.id),
:cancel_return_url => url_for(:action => 'show', :controller => "orders",:id => order.id),
:allow_guest_checkout => true,
:items =>
[{ :name => current_user.to_s,
:quantity => 1,
:description => "Items",
:amount => amount
}]
)
if response.present?
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end
end
def complete
order = current_user.orders.find(params[:id])
amount = order.total_amount
begin
purchase = EXPRESS_GATEWAY.purchase(amount,
:ip => request.remote_ip,
:payer_id => params[:PayerID],
:token => params[:token]
)
rescue Exception => e
logger.error "Paypal error while creating payment: #{e.message}"
flash[:error] = e.message
end
unless purchase.success?
flash[:error] = "Unfortunately an error occurred:" + purchase.message
else
flash[:notice] = "Thank you for your payment"
end
redirect_to :action => "show", :id => order.id
end

ThinkingSphinx excerpt issue with associations with special chars

I'm having an issue with special characters (apostrophe, namely), only when present is a nested association, however.
I have a 'Vendor' model and an 'Event' model, where a Vendor has_many Events. Here are the index files:
vendor_index:
ThinkingSphinx::Index.define :vendor, :with => :active_record do
indexes :name
indexes city
set_property :min_prefix_len => 2
set_property :enable_star => true
end
event_index:
ThinkingSphinx::Index.define :event, :with => :active_record do
indexes title
indexes subtitle
indexes venue_name
indexes vendor.name, :as => :vendor_name
indexes vendor.city, :as => :vendor_city
indexes genre.name, :as => :genre_name
where "workflow_state = 'published'"
set_property :min_prefix_len => 2
set_property :enable_star => true
end
I'm using an ExcerptorPane, like so, in my search#index action :
class SearchController < ApplicationController
helper_method :format_autocomplete
def index
#events = Event.search params[:search], {:star => true , :per_page => 5, :page => params[:events_page]}
#events.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
#vendors = Vendor.search params[:search], { :star => true , :per_page => 5, :page => params[:vendors_page]}
#vendors.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
#users = User.search params[:search], { :star => true , :per_page => 5, :page => params[:users_page]}
#users.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
end
# methods used for ajax-y pagination
def vendor_results
#vendors = Vendor.search params[:search], { :star => true , :per_page => 5, :page => params[:vendors_page]}
#vendors.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
respond_to do |format|
format.js
end
end
def user_results
#users = User.search params[:search], { :star => true , :per_page => 5, :page => params[:users_page]}
#users.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
respond_to do |format|
format.js
end
end
def event_results
#events = Event.search params[:search], { :star => true , :per_page => 5, :page => params[:events_page]}
#events.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
respond_to do |format|
format.js
end
end
def get_terms
results = ThinkingSphinx.search(params[:search], {:star => true})
results.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
results_json = format_autocomplete(results)
respond_to do |format|
format.js { render :json => results_json }
end
end
private
def format_autocomplete(r)
bucket = [];
r.each do |result|
puts result.class
if result.class.name == "Event"
title = result.excerpts.title
name = result.excerpts.vendor_name
bucket << {
:label => title,
:value => title,
:category => "Events",
:subtitle => result.excerpts.subtitle,
:url => event_url(result),
:vendor_name => name,
:vendor_city => result.excerpts.vendor_city,
:genre_name => result.excerpts.genre_name,
:venue_name => result.excerpts.venue_name
}
elsif result.class.name == "Vendor"
name = result.excerpts.name
bucket << {
:label => name,
:value => name,
:category => "Vendors",
:subtitle => result.excerpts.city,
:url => vendor_url(result)
}
elsif result.class.name == "User"
name = result.excerpts.name
bucket << {
:label => name,
:value => name,
:category => "Users",
:subtitle => result.excerpts.city,
:url => user_url(result)
}
end
end
bucket
end
end
I have also included a charset_table and ignore_chars in my thinking_sphinx.yml file.
Now, when I search for a Vendor with an apostrophe in their name, everything goes fine if the Vendor has no events. If a Vendor has events though, I get an error trying to render the event's vendor_name: (the full vendor name is "VIFF's Vancity Theatre, and the search query is 'viff')
sphinxql: syntax error, unexpected IDENT, expecting ')' near 's Vancity Theatre', 'event_core', '*viff*', '<span class="match">' AS before_match, '</span>' AS after_match, ' … ' AS chunk_separator)'
raised at this line in my view:
<p><%= link_to ( raw event.excerpts.vendor_name ), vendor_path(event.vendor) %></p>
I've been searching for a while, but can't find anything of help...Any ideas as to what might be causing this?
Thanks!
UPDATE:
It gets weirder ... with vendor name "Viff's Vancity Theatre", (and all events and vendors have city = 'Vancouver' ) if I search "van" or "vanc", everything renders fine, with "Vancity" marked as a match. However if I search "vanco" it breaks again. This happens when I am performing a search on specific models. When I perform a global search however (for autocomplete), I get the opposite behaviour - 'vanco' will work, but anything shorter throws back the same error. I've updated the code above with the full search_controller.rb.
I just received a pull request for Riddle that may contain a fix for this. Try adding the following to your Gemfile:
gem 'riddle', '~> 1.5.6',
:git => 'git://github.com/pat/riddle.git',
:branch => 'master',
:ref => '50d410cda6'

AJAX update of accepts_nested_attributes_for partials

My current working environment is Rails 2.3.8 (various reasons why my company hasn't moved to Rails 3).
I'm trying to update elements of a multi-model form via AJAX calls - the idea being to replace certain dropdowns depending on how the user selects or fills in other fields.
I have previously managed to get this working by using non-form based partials - the problem I have now is to reproduce the AJAX updating of the select dropdowns when the partials are based around form_for and fields_for.
Sorry for the following wall of text - i've tried to cut it down as much as possible (the code itself does work on my test site).
How do I generate the form builder elements in the Outbreak controller and then pass this to the category partial to take the place of incident_form?
Any pointers would be great :D
Models
class Outbreak < ActiveRecord::Base
has_many :incidents, :dependent => :destroy
has_many :locations, :through => :incidents
accepts_nested_attributes_for :locations, :allow_destroy => true, :reject_if => :all_blank
accepts_nested_attributes_for :incidents, :allow_destroy => true, :reject_if => :all_blank
end
class Incident < ActiveRecord::Base
belongs_to :outbreak
belongs_to :location
belongs_to :category
belongs_to :subcategory
belongs_to :subtype
end
class Location < ActiveRecord::Base
has_many :incidents, :dependent => :destroy
has_many :outbreaks, :thorugh => incidents
end
Views
_form
<% form_for(#outbreak, :html => {:multipart => true}) do |form| %>
<%= render :partial => 'outbreak_type_select', :locals => {:outbreak_types => #outbreak_types, :f => form } %>
<% form.fields_for :incidents do |incident_form| %>
<%= render :partial => 'category_select', :locals => {:categories => #categories, :incident_form => incident_form} %>
<%= render :partial => 'subcategory_select', :locals => { :subcategories => #subcategories, :incident_form => incident_form } %>
<% end %>
<% end %>
_outbreak_type_select
<% with_str = "'outbreak_type=' + value " %>
<% if #outbreak.id %>
<% with_str << "+ '&id=' + #{outbreak.id}" %>
<% end %>
<%= f.collection_select(:outbreak_type, #outbreak_types, :property_value, :property_value, {}, {:onchange => "#{remote_function(:url => { :action => "update_select_menus"}, :with => with_str)}"} ) %>
_category_select
After calling update_select_menus how to generate the incident_form
<%= incident_form.collection_select( :category_id, #categories, :id, :name, {:prompt => "Select a category"}, {:onchange => "#{remote_function(:url => { :action => "update_subcategory"}, :with => "'category_id='+value")}"}) %>
RJS
begin
page.replace_html 'outbreak_transmission_div', :partial => 'outbreaks/transmission_mode_select', :locals => {:transmission_modes => #transmission_modes }
rescue
page.insert_html :bottom, 'ajax_error', '<p>Error :: transmission modes update select</p>'
page.show 'ajax_error'
end
begin
page.replace_html 'incident_category_select', :partial => 'outbreaks/category_select', :locals => { :categories => #categories }
rescue
page.insert_html :bottom, 'ajax_error', '<p>Error :: incident category update select</p>'
page.show 'ajax_error'
end
Controllers
Outbreak
def new
#outbreak = Outbreak.new
#outbreak.incidents.build
#outbreak.locations.build
#just the contents for the dropdowns
#categories = Category.find(:all, :conditions => {:outbreak_type => "FOODBORNE"}, :order => "outbreak_type ASC")
#subcategories = Subcategory.find(:all, :order => "category_id ASC")
end
def update_select_menus
#outbreak_type = params[:outbreak_type].strip
if params[:id]
#outbreak = Outbreak.find(params[:id])
else
#outbreak = Outbreak.new
#outbreak.incidents.build
#outbreak.locations.build
end
if #outbreak_type == "FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
elsif #outbreak_type == "NON-FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "NON-FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
end
respond_to do |format|
format.html
format.js
end
end
Found a work around based on http://www.treibstofff.de/2009/07/12/ruby-on-rails-23-nested-attributes-with-ajax-support/
This should probably go in Outbreak helper (in Outbreak controller atm)
def update_select_menus
#outbreak_type = params[:outbreak_type].strip
#next_child_index will only be used if
#next_child_index ? params[:next_child_index] : 0
if params[:id]
#outbreak = Outbreak.find(params[:id])
else
#outbreak = Outbreak.new
#outbreak.risks.build
#outbreak.incidents.build
#outbreak.locations.build
end
if #outbreak_type == "FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
elsif #outbreak_type == "NON-FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "NON-FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
end
#pathogen_types = Property.find(:all, :conditions => {:field => "PATHOGENS:CATEGORY"})
#outbreak_types = Property.find(:all, :conditions => {:field => "OUTBREAKS:OUTBREAK_TYPE"} )
render :update do |page|
page.replace 'outbreak_transmission_div', :partial => 'transmission_mode_select_update'
page.replace 'incident_category_select', :partial => 'incident_category_select_update'
page.replace 'incident_subcategory_select', :partial => 'incident_subcategory_select_update'
page.replace 'incident_subtype_select', :partial => 'incident_subtype_select_update'
end
end
In the Outbreak view (although since this partial is related to Incident it should probably go in that view instead)
<% ActionView::Helpers::FormBuilder.new(:outbreak, #outbreak, #template, {}, proc{}).fields_for :incidents,{:child_index => #next_child_index} do |this_form| %>
<div id="incident_category_select">
<%= render :partial => 'category_select', :locals => {:incident_form => this_form } %>
</div>
<% end %>
The ActionView::Helpers::FormBuilder is used to produce the required fields_for form - The website article goes through this in more detail.
The resulting index is set by the #next_child_index variable which can be passed to the controller by the original AJAX call (for example #next_child_index = 1, then the resulting form element name will be outbreak [incidents_attributes] [1] [category_id] ) - I haven't used this in this example because although in future I want the form to support more than one location per Outbreak for this initial run-through it will just accept a single Location - Incident per Outbreak.
_category_select.erb partial (in Outbreak view atm)
<% with_str = "'category_id=' + value " %>
<% if #outbreak.id %>
<% with_str << "+ '&id=' + #{#outbreak.id}" %>
<% end %>
<%= incident_form.collection_select( :category_id, #categories, :id, :name, {:prompt => "Select a category"}, {:onchange => "#{remote_function(:url => { :action => "update_subcategory"}, :with => with_str)}"}) %>
The with_str is just to optionally pass the Outbreak id if it exists to the controller to find the Outbreak record to produce the form and if not to build a new Outbreak and associated nested attributes like Incidents and Locations.
The must be neater ways of doing this - especially the FormHelper and passing the Outbreak id via the optional with string.

Resources