Couldn't find Tour without an ID - ruby-on-rails

I'm working on an app to book different types of tours. I have 3 tables - 1) reservations 2) tours 3) join table (reservations_tours). I'm trying to pass the tour id to reservations, but keep getting this error:
Couldn't find Tour without an ID
app/controllers/reservations_controller.rb:12:in `create'
Reservations controller:
class ReservationsController < ApplicationController
def index
end
def new
#reservation = Reservation.new
#tour = Tour.find(params[:tour_id])
end
def create
#tour = Tour.find(params[:tour_id])
#reservation = Reservation.new(reservation_params)
##reservation.tour = #tour # associate #reservation with video
if #reservation.save
Stripe.api_key = ENV["STRIPE_SECRET_KEY"]
Stripe::Charge.create(
:amount => 9000, # amount in cents, again
:currency => "usd",
:card => params[:stripeToken] # Get the credit card details submitted by the form
)
flash[:success] = "Your reservation has been booked for #{#reservation.date} for #{#reservation.passengers} person(s). Please save this info."
redirect_to new_tour_path
else
render 'new'
end
end
private
def reservation_params
params.require(:reservation).permit(:date, :passengers)
end
end
Tours controller:
class ToursController < ApplicationController
def index
end
def new
#tour = Tour.new
end
def create
#tour = Tour.new(tours_params)
if #tour.save
flash[:success] = "Tour #{#tour.name} has been successfully added."
redirect_to new_tour_path
else
flash[:error] = "The tour #{#tour.name} was not successfully saved. Please try again"
render 'new'
end
end
def show
#tour = Tour.find_by(id: params[:id])
#reservation = Reservation.new
end
def edit
end
def update
end
private
def tours_params
params.require(:tour).permit(:name, :amount)
end
end
Reservations view (new)
= javascript_include_tag "https://js.stripe.com/v2/"
= javascript_include_tag 'payment'
:javascript
Stripe.setPublishableKey("#{ENV['STRIPE_PUBLISHABLE_KEY']}");
.container
.row
.col-md-9
%h2= #tour.name
.col-md-3
%p= #tour.amount
= bootstrap_form_for(#reservation, html: { class: 'form-horizontal', id: 'payment-form'}) do |f|
= f.alert_message 'Please fix the errors below:'
= f.text_field :date
= f.text_field :passengers
%fieldset.credit_card
%span.payment-errors
.control-group
= label_tag :card_number, 'Credit card number:', class: 'control-label'
.controls
= text_field_tag :card_number, nil, name: nil, class: 'span3', data: {stripe: 'number'}
.control-group
= label_tag :security_code, 'Security code:', class: 'control-label'
.controls
= text_field_tag :security_code, nil, name: nil, class: 'span3', data: {stripe: 'cvc'}
.control-group
= label_tag :exp_date, 'Expiration:', class: 'control-label'
.controls
= select_month(Date.today, {add_month_numbers: true}, class: 'span2', data: {stripe: 'exp-month'})
= select_year(Date.today.year, {start_year: Date.today.year, end_year: Date.today.year + 4}, class: 'span1', data: {stripe: 'exp-year'})
%fieldset.actions.control-group
.controls
= f.submit 'Sign up'
Reservation model:
class Reservation < ActiveRecord::Base
has_many :reservations_tours, foreign_key: 'reservation_id'
has_many :tours, through: :reservations_tours
end
Tour model
class Tour < ActiveRecord::Base
has_many :reservations_tours, foreign_key: 'tour_id'
has_many :reservations, through: :reservations_tours
end
Join table
class ReservationsTours < ActiveRecord::Base
belongs_to :reservation, foreign_key: 'reservation_id'
belongs_to :tour, foreign_key: 'tour_id'
end
Routes:
Rails.application.routes.draw do
resources :reservations, only: [:new, :create]
resources :tours
end

You are trying to create a non existing relation. You have two basic options to create a relation in rails:
Provide a dropdown with existing tours in the reservations form
f.collection_select(:tour_id, Tour.all, :id, :name)
it will become available in the params[:reservation] array. You will have to permit the tour_id param in reservation_params
make a nested resource for reservations in config/routes.rb.
resources :tours do
resources :reservations
end
which will give you a POST url like /tours/:tour_id/reservations and provide you with params[:tour_id]

Related

RoR: Enums, how to list recipients of a message based on them

I have an application that allows a user to send a message to other users. I have two user types defined as enums in user rb- teacher and student:
enum access_level: [:student, :teacher]
I am wondering how to get the desired recipients to appear in a list in the view (below) so that a teacher can only send to students or the other way round.
In my messages controller I have:
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#chosen_recipient = User.find_by(id: params[:to].to_i) if params[:to]
end
def create
recipients = User.where(id: params['recipients'])
conversation = current_user.send_message(recipients, params[:message][:body], params[:message][:subject]).conversation
flash[:success] = "Message has been sent!"
redirect_to conversation_path(conversation)
end
end
And my conversations controller:
class ConversationsController < ApplicationController
before_action :authenticate_user!
before_action :get_mailbox
before_action :get_conversation, except: [:index, :empty_trash]
before_action :get_box, only: [:index]
def index
if #box.eql? "inbox"
#conversations = #mailbox.inbox
elsif #box.eql? "sent"
#conversations = #mailbox.sentbox
else
#conversations = #mailbox.trash
end
#conversations = #conversations.paginate(page: params[:page], per_page: 10)
end
def show
end
def mark_as_read
#conversation.mark_as_read(current_user)
flash[:success] = 'The conversation was marked as read.'
redirect_to conversations_path
end
def reply
current_user.reply_to_conversation(#conversation, params[:body])
flash[:success] = 'Reply sent'
redirect_to conversation_path(#conversation)
end
def destroy
#conversation.move_to_trash(current_user)
flash[:success] = 'The conversation was moved to trash.'
redirect_to conversations_path
end
def restore
#conversation.untrash(current_user)
flash[:success] = 'The conversation was restored.'
redirect_to conversations_path
end
def empty_trash
#mailbox.trash.each do |conversation|
conversation.receipts_for(current_user).update_all(deleted: true)
end
flash[:success] = 'Your trash was cleaned!'
redirect_to conversations_path
end
private
def get_mailbox
#mailbox ||= current_user.mailbox
end
def get_conversation
#conversation ||= #mailbox.conversations.find(params[:id])
end
def get_box
if params[:box].blank? or !["inbox","sent","trash"].include?(params[:box])
params[:box] = 'inbox'
end
#box = params[:box]
end
end
My view (messages/_form.html.erb):
<%= form_tag messages_path, method: :post do %>
<div class="form-group">
<%= label_tag 'message[subject]', 'Subject' %>
<%= text_field_tag 'message[subject]', nil, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'message[body]', 'Message' %>
<%= text_area_tag 'message[body]', nil, cols: 3, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'recipients', 'Choose recipients' %>
<%= select_tag 'recipients', recipients_options(#chosen_recipient), multiple: true, class: 'form-control chosen-it' %>
</div>
<%= submit_tag 'Send', class: 'btn btn-primary' %>
<% end %>
How would I get the list to appear based on the enum attribute associated with the user? A teacher could only see students for example.
Appreciate any guidance. Thanks.
Here are the methods given by the enum,
class User < ActiveRecord::Base
enum access_level: [ :student, :teacher ]
end
user.student!
user.student? # => true
user.access_level # => "student"
user.teacher!
user.teacher? # => true
user.access_level # => "teacher"
So you can use,
def new
if params[:to].present?
render text: params and return false
#chosen_recipient = current_user.student? ? check_access_level('teacher') : check_access_level('student')
end
end
private
def check_access_level(access_level)
User.where(id: params[:to].to_i, access_level: access_level)
end
Try this,
def new
#chosen_recipient = current_user.student? (User.where(id: params[:to].to_i, access_level: 1)) : current_user.teacher? (User.where(id: params[:to].to_i, access_level: 0)) if params[:to]
end
Have you tried changing the method that generates the chosen recipients? In helpers/messages_helpers.rb change the method as follows:
User.teacher.each do |user|
s << "leave this the way it is"
end
You can also do as Navin suggested and just check if the current user is a teacher. I would just put a variable as follows
if user.teachers?
reciepients = User.all
else
reciepients = User.teachers?
end
Then we can do as follows:
recipients.each do |user|
s << "leave this the way it is"
end
Hope that points you in the right direction.

Rails nested routes for create method smart_listing

I have two models: apartment and room. Apartment has_many rooms, and rooms belongs_to apartment. I use smart_listing gem as ajax form. I show my table in edit_apartment_path
= render 'rooms/index' # index is partial
And I add this to my apartment_controller
def edit
#rooms = smart_listing_create :rooms,
Room.where(apartment_id: params[:apartment_id]),
partial: "rooms/list"
end
Now I must set paths for my form
= simple_form_for object, url: object.new_record? ? apartment_rooms_path : apartment_room_path(id: object),
remote: true, html: {class: "form-horizontal"} do |f|
= f.input :title
= f.button :submit
I can edit my created room, but I can't create new room in apartment. My error:
ActionController::UrlGenerationError - No route matches {:action=>"edit", :apartment_id=>nil, :controller=>"rooms", :id=>#<Room id: 83, title: "dawawd">, created_at: "2016-02-11 10:36:30", updated_at: "2016-02-11 10:36:30", apartment_id: 4>} missing required keys: [:apartment_id]:
My routes
resources :apartments do
resources :rooms
end
Propably smart_listing not support nested routes. Anyone have idea? :)
here's simple example of nested routes with smart_listing. I think that should cover the subject.
I used Rails 4.2, ruby 2.2.0, smart_listing 1.1.2
config/routes.rb
resources :users do
resources :bios
end
root 'users#index'
models/user.rb
class User < ActiveRecord::Base
has_one :bio
accepts_nested_attributes_for :bio, allow_destroy: true
scope :like, ->(args) { where("email like '%#{args}%' OR name like '%#{args}%' OR surname like '%#{args}%'")}
end
models/bio.rb
class Bio < ActiveRecord::Base
belongs_to :user
end
controllers/users_controller.rb
class UsersController < ApplicationController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
before_action :set_user, only: [:update, :destroy]
def index
users_scope = User.all.includes(:bio)
users_scope = users_scope.like(params[:filter]) if params[:filter]
# #users = smart_listing_create :users, users_scope, partial: "users/list", page_sizes: [5, 7, 13, 26]
#users = smart_listing_create(:users, users_scope, partial: 'users/list',
sort_attributes: [
[:name, 'name'],
[:surname, 'surname'],
[:email, 'email'],
[:city, 'bio.city'],
[:birthday, 'bio.birthday']
],
default_sort: { start_at: 'desc' }
)
end
def new
#user = User.new
#user.build_bio
end
def create
#user = User.new(user_params)
#user.save
end
def edit
#user = User.includes(:bio).find(params[:id])
#user.bio.build if #user.bio.nil?
end
def update
#user.update(user_params)
end
def delete
end
def destroy
#user.destroy
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :surname, :email, :bio_attributes => [:birthday, :city])
end
end
views/users/index.html.haml
= smart_listing_controls_for(:users, {class: "form-inline text-right"}) do
.form-group.filter.input-append
= text_field_tag :filter, '', class: "search form-control",
placeholder: "Search...", autocomplete: :off
= smart_listing_render :users
views/users/_list.html.haml
- unless smart_listing.empty?
%table.table.table-striped
%thead
%th= smart_listing.sortable "Name", :name
%th= smart_listing.sortable "Surname", :surname
%th= smart_listing.sortable "Email", :email
%th= smart_listing.sortable "City", :city
%th= smart_listing.sortable "Birthday", :birthday
%tbody
- smart_listing.collection.each do |o|
%tr.editable{data: {id: o.id}}
= smart_listing.render object: o, partial: "users/user", locals: {object: o}
= smart_listing.item_new colspan: 6, link: new_user_path
= smart_listing.paginate
= smart_listing.pagination_per_page_links
- else
%p.warning No users
views/users/_user.html.haml
%td= object.name
%td= object.surname
%td= object.email
%td= object.bio.city
%td= object.bio.birthday
%td.actions= smart_listing_item_actions [ {name: :edit, url: edit_user_path(object)}, {name: :destroy, url: user_path(object), confirmation: "Are you sure you want to delete this?"}]
views/users/_form.html.haml
%td{colspan: 6}
= form_for object, url: object.new_record? ? users_path : user_path(object),
remote: true, html: {class: "form-horizontal"} do |f|
%p
Name:
= f.text_field :name
%p
Surname:
= f.text_field :surname
%p
Email:
= f.text_field :email
= f.fields_for :bio do |ff|
%p
Birthday
= ff.date_field :birthday
%p
City
= ff.text_field :city
= f.submit "Save", class: "btn btn-primary"
%button.btn.btn-link.cancel Cancel
views/users/create.js.erb
<%= smart_listing_item :users, :create, #user, #user.persisted? ? "users/user" : "users/form" %>
views/users/edit.js.erb
<%= smart_listing_item :users, :edit, #user, "users/form" %>
views/users/destroy.js.erb
<%= smart_listing_item :users, :destroy, #user %>
views/users/index.js.erb
<%= smart_listing_update(:users) %>
views/users/new.js.erb
<%= smart_listing_item :users, :new, #user, "users/form" %>
views/users/update.js.erb
<%= smart_listing_item :users, :update, #user, #user.valid? ? "users/user" : "users/form" %>
you should receive to form #apartment also, and in this case if your #room.persisted? form recive request to edit, else to create:
= simple_form_for [#apartment, #room], remote: true, html: {class: "form-horizontal"} do |f|
= f.input :title
= f.button :submit

How to validate a child object attributes when self-reference association?

I have a one model 'Task' and have two entities - 'tasks' and 'subtasks' with self-reference association.
class Task < ActiveRecord::Base
has_many :subtasks, class_name: 'Task', foreign_key: 'parent_id', dependent: :destroy
belongs_to :parent, class_name: 'Task'
accepts_nested_attributes_for :subtasks, allow_destroy: true
validates :title, presence: true, length: { minimum: 3 }
validates :priority, presence: true, numericality: { only_integer: true }, length: { is: 1 }
validates_associated :subtasks
end
And i use one controller - TasksController.
class TasksController < ApplicationController
before_action :find_task, only: [:show, :edit, :update, :destroy, :run, :complete]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_task
def run
#task.run!
redirect_to :back
end
def complete
#task.complete!
redirect_to :back
end
def index
#tasks = Task.all
end
def show
end
def new
#task = Task.new
end
def edit
end
def create
#task = Task.create(task_params)
if #task.errors.empty?
redirect_to tasks_path, notice: "Task created!"
else
render 'new', notice: "Invalid input!"
end
end
def update
#task.update_attributes(task_params)
if #task.errors.empty? || :subtasks_attributes?
redirect_to #task
else
render 'edit'
end
end
def destroy
#task.destroy
if #task.parent_id?
redirect_to #task.parent
else
redirect_to tasks_path
end
end
private
def task_params
params.require(:task).permit(:title, :description, :scheduled, :deadline, :priority, :project, subtasks_attributes: [:title, :priority])
end
def find_task
#task = Task.find(params[:id])
end
def invalid_task
redirect_to tasks_path, notice: "Invalid task!"
end
end
I wanna create subtasks on task show page:
- #task.subtasks.each do |subtask|
- if subtask.in_work?
=> link_to 'Complete', complete_task_path(subtask), method: :put
- else
=> link_to 'Run', run_task_path(subtask), method: :put
=> subtask.title
=> link_to 'Edit', edit_task_path(subtask)
= link_to 'Delete', [subtask], method: :delete, data: { confirm: 'Are you sure?' }
= simple_form_for #task do |t|
= t.simple_fields_for :subtasks, #task.subtasks.build do |f|
.form-inputs
= f.input :title
= f.hidden_field :priority, value: #task.priority
.form-actions
= f.button :submit, "Add a subtask"
Now on the task show page i can create a subtask with valid attributes and can't create a subtask with invalid attributes, but i do not get validation message.
How can i fix it?
Ty and sorry for my English.
PS:
i don't know why, but errors exist inside controller and doesn't exist inside view
#project.update_attributes(project_params)
puts #project.errors.full_messages
if #project.errors.empty? || :tasks_attributes?
redirect_to #project
puts #project.errors.full_messages
(0.0ms) begin transaction
(0.0ms) rollback transaction
Tasks title can't be blank
Tasks title is too short (minimum is 3 characters)
Redirected to http://localhost:3000/projects/3
Tasks title can't be blank
Tasks title is too short (minimum is 3 characters)
Completed 302 Found in 6ms (ActiveRecord: 0.2ms)
You should add the errors messages to the view too:
= simple_form_for #task do |t|
= t.simple_fields_for :subtasks, #task.subtasks.build do |f|
#error message added here
- if #task.subtasks.errors.any?
%ul.errors
- #task.subtasks.errors.full_messages.each do |msg|
%li= msg
.form-inputs
= f.input :title
= f.hidden_field :priority, value: #task.priority
.form-actions
= f.button :submit, "Add a subtask"
EDIT
You have a _form partial in you application, change that code to this
= simple_form_for #task do |f|
- if #task.errors.any?
ul.errors
- #task.errors.full_messages.each do |msg|
=> msg
= f.input :title
= f.input :description
= f.input :scheduled
= f.input :deadline
= f.input :priority, collection: [["None", 0], ["High", 3], ["Medium", 2], ["Low", 1]], selected: ["None"]
= f.button :submit

Why I get Unpermitted parameters error when I try to save with HABTM check_box_tag?

Ruby version :
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
Rails version :
Rails 4.1.4
I have a HABTM association between two models : Product and Page. This association works well when I use the console with the following command :
Product.first.pages << Page.first
I inserted a check_box_tag in my products/_form.html.haml for displaying my pages. The check_box works well and I can check/uncheck all my pages.
The problem is when I try to submit the form, the modifications I have done in the checkbox are not saved. I have this problem in both ways.
I figured the problem is the Unpermitted parameters error in my log.
Started PATCH "/admin/pages/linge-de-lit" for 127.0.0.1 at 2014-09-23 23:13:40 +0200
Processing by Admin::PagesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"q/ZskL+Zijc8GMX9lF+EPgqc9uic9N9B/isWYHx7Cx0=", "page"=>{"category"=>"fabric", "title"=>"Linge de lit", "intro"=>"", "visibility"=>"1", "favorite"=>"0", "priority"=>"50", "product_ids"=>["", "1", "2"]}, "commit"=>"Save", "id"=>"linge-de-lit"}
Page Load (0.3ms) SELECT "pages".* FROM "pages" WHERE "pages"."slug" = 'linge-de-lit' ORDER BY "pages"."id" ASC LIMIT 1
Unpermitted parameters: product_ids
(0.3ms) begin transaction
Page Exists (0.3ms) SELECT 1 AS one FROM "pages" WHERE ("pages"."title" = 'Linge de lit' AND "pages"."id" != 5) LIMIT 1
(0.2ms) commit transaction
Redirected to http://localhost:3000/admin/pages/linge-de-lit
Completed 302 Found in 86ms (ActiveRecord: 1.1ms)
I think the problem is my strong parameters but I doesn't see where.
Here is my models :
class Product < ActiveRecord::Base
has_and_belongs_to_many :pages
end
class Page < ActiveRecord::Base
has_and_belongs_to_many :products
has_many :posts
validates :category, presence: true
validates :title, presence: true, length: {maximum: 20}, uniqueness: true
extend FriendlyId
friendly_id :title, :use => [:slugged, :finders]
before_save :default_values
def default_values
self.title = self.title.capitalize
end
#Scopes
scope :visible, -> { where(visibility: true) }
scope :favorite, -> { where(favorite: true) }
end
Here is my controllers :
class Admin::ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /admin/products
def index
#products = Product.all
end
# GET /admin/products/1
def show
end
# GET /admin/products/new
def new
#product = Product.new
#pages = Page.all
end
# GET /admin/products/1/edit
def edit
#pages = Page.all
end
# POST /admin/products
def create
#product = Product.new(product_params)
if #product.save
redirect_to [:admin, #product], notice: 'Product was successfully created.'
else
render action: 'new'
end
end
# PATCH/PUT /admin/products/1
def update
if #product.update(product_params)
redirect_to [:admin, #product], notice: 'Product was successfully updated.'
else
render action: 'edit'
end
end
# DELETE /admin/products/1
def destroy
#product.destroy
redirect_to admin_products_url, notice: 'Product was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def product_params
params.require(:product).permit(:name, :description, :brand_id, :price, :minimum_price, :shop_disponibility, :web_disponibility, :purchase_link, :favorite, {:pages_ids => []})
end
end
class Admin::PagesController < ApplicationController
before_action :set_page, only: [:show, :edit, :update, :destroy]
# GET /admin/pages
def index
#pages = Page.all
end
# GET /admin/pages/1
def show
end
# GET /admin/pages/new
def new
#page = Page.new
#products = Product.all
end
# GET /admin/pages/1/edit
def edit
#products = Product.all
end
# POST /admin/pages
def create
#page = Page.new(page_params)
if #page.save
redirect_to [:admin, #page], notice: 'Page was successfully created.'
else
render action: 'new'
end
end
# PATCH/PUT /admin/pages/1
def update
if #page.update(page_params)
redirect_to [:admin, #page], notice: 'Page was successfully updated.'
else
render action: 'edit'
end
end
# DELETE /admin/pages/1
def destroy
#page.destroy
redirect_to admin_pages_url, notice: 'Page was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_page
#page = Page.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def page_params
params.require(:page).permit(:category, :title, :intro, :visibility, :favorite, :priority, :products_ids => [])
end
end
Here is my views :
# products/_form
= form_for([:admin, #product]) do |f|
- if #product.errors.any?
#error_explanation
%h2= "#{pluralize(#product.errors.count, "error")} prohibited this product from being saved:"
%ul
- #product.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :name
= f.text_field :name
.field
= f.label :description
= f.text_area :description
.field
= f.label :brand_id
= f.text_field :brand_id
.field
= f.label :price
= f.text_field :price
.field
= f.label :minimum_price
= f.check_box :minimum_price
.field
= f.label :shop_disponibility
= f.check_box :shop_disponibility
.field
= f.label :web_disponibility
= f.check_box :web_disponibility
.field
= f.label :purchase_link
= f.text_field :purchase_link
.field
= f.label :favorite
= f.check_box :favorite
= hidden_field_tag "product[page_ids][]", nil
- Page.all.each do |page|
= check_box_tag "product[page_ids][]", page.id, #product.page_ids.include?(page.id), id: dom_id(page)
= label_tag dom_id(page), page.title
.actions
= f.submit 'Save'
# pages/_form
= form_for([:admin, #page]) do |f|
- if #page.errors.any?
#error_explanation
%h2= "#{pluralize(#page.errors.count, "error")} prohibited this page from being saved:"
%ul
- #page.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :category
= f.select :category, options_for_select(#pages_categories), {:prompt => "- Sélectionner une catégorie -"}
.field
= f.label :title
= f.text_field :title
.field
= f.label :intro
= f.text_area :intro
.field
= f.label :visibility
= f.check_box :visibility
.field
= f.label :favorite
= f.check_box :favorite
.field
= f.label :priority
= f.number_field :priority
= hidden_field_tag "page[product_ids][]", nil
- Product.all.each do |product|
= check_box_tag "page[product_ids][]", product.id, #page.product_ids.include?(product.id), id: dom_id(product)
= label_tag dom_id(product), product.name
.actions
= f.submit 'Save'
There is a typo there :) Instead of
# Only allow a trusted parameter "white list" through.
def page_params
params.require(:page).permit(:category, :title, :intro, :visibility, :favorite, :priority, :products_ids => [])
end
It should be product_ids:
# Only allow a trusted parameter "white list" through.
def page_params
params.require(:page).permit(:category, :title, :intro, :visibility, :favorite, :priority, :product_ids => [])
end

Using attributes from one model in another Rails

I apologize that this is such a simplistic question, but I've been struggling with it for a while.
I have two related models - Tour & Reservation. "Tour" has a "days" attribute. I want to list the days in a select tag for the user to choose from in my "Reservation" view
I thought this might work:
(Reservations controller) #tour_days = Tour.where(:days => params[:days])
(Reservations #new) = f.select :days, #tours_days
However, I'm receiving the error undefined methoddays' `
class Reservation < ActiveRecord::Base
belongs_to :tour
end
class Tour < ActiveRecord::Base
has_many :reservations
end
.
class ReservationsController < ApplicationController
def index
end
def new
#reservation = Reservation.new
#tour = Tour.find(params[:tour_id])
#tour_days = Tour.where(:days => params[:days])
end
def create
#tour = Tour.find(params[:tour_id])
if #reservation.update_attribute(:t_shirt, params[:t_shirt]) == true || #reservation.update_attribute(:hat, params[:hat]) == true
#tour.amount = #tour.amount + 15
else
#tour.amount = #tour.amount
end
#reservation = Reservation.new(reservation_params)
if #reservation.save
Stripe.api_key = ENV["STRIPE_SECRET_KEY"]
Stripe::Charge.create(
:amount => #tour.amount, # amount in cents, again
:currency => "usd",
:card => params[:stripeToken]
)
flash[:success] = "Your reservation has been booked for #{#reservation.passengers} person(s). Please save this info."
redirect_to new_tour_reservation_path(#tour)
else
render 'new'
end
end
private
def reservation_params
params.require(:reservation).permit(:passengers, :t_shirt, :hat)
end
end
.
class ToursController < ApplicationController
def index
#tours = Tour.all
end
def new
#tour = Tour.new
end
def create
#tour = Tour.new(tours_params)
if #tour.save
flash[:success] = "Tour #{#tour.name} has been successfully added."
redirect_to new_tour_path
else
flash[:error] = "The tour #{#tour.name} was not successfully saved. Please try again"
render 'new'
end
end
def show
#tour = Tour.find_by(id: params[:id])
#reservation = Reservation.new
end
def edit
#tour = Tour.find_by(id: params[:id])
end
def update
#tour = Tour.find_by(id: params[:id])
if #tour.update_attributes(tours_params)
flash[:success] = "#{#tour.name} has been successfully updated."
redirect_to tours_path
else
flash[:error] = "#{#tour.name} has not been updated. Please try again."
render 'edit'
end
end
def delete
#tour = Tour.find_by(id: params[:id])
end
def destroy
#tour = Tour.find_by(id: params[:id])
if #tour.destroy
flash[:success] = "The #{#tour.name} has been successfully deleted."
redirect_to tours_path
else
flash[:error] = "The #{#tour.name} has not been deleted. Please try again."
render 'edit'
end
end
private
def tours_params
params.require(:tour).permit(:name, :amount, :days)
end
end
.
= bootstrap_form_for([:tour, #reservation], html: { class: 'form-horizontal', id: 'payment-form'}) do |f|
= f.alert_message 'Please fix the errors below:'
= f.select :passengers, options_for_select( (1..10).map { |n| n %1 == 0 ? n.to_i : n } )
= f.select :days, #tours_days
%fieldset.credit_card
%span.payment-errors
.control-group
= label_tag :card_number, 'Credit card number:', class: 'control-label'
.controls
= text_field_tag :card_number, nil, name: nil, class: 'span3', data: {stripe: 'number'}
.control-group
= label_tag :security_code, 'Security code:', class: 'control-label'
.controls
= text_field_tag :security_code, nil, name: nil, class: 'span3', data: {stripe: 'cvc'}
.control-group
= label_tag :exp_date, 'Expiration:', class: 'control-label'
.controls
= select_month(Date.today, {add_month_numbers: true}, class: 'span2', data: {stripe: 'exp-month'})
= select_year(Date.today.year, {start_year: Date.today.year, end_year: Date.today.year + 4}, class: 'span1', data: {stripe: 'exp-year'})
%fieldset.actions.control-group
.controls
= f.submit 'Sign up'
consider using accepts_nested_attributes_for
Create another model to encapsulate the days. Then associate it with the Reservation model.
class Reservation < ActiveRecord::Base
belongs_to :tour
has_and_belongs_to_many :days
accepts_nested_attributes_for :days, allow_destroy: true
end
class Day < ActiveRecord::Base
has_and_belongs_to_many :reservations
end
The Day model will have one attribute: name which will hold the names of the seven days
class ReservationsController < ApplicationController
def create
#reservation = Reservation.new(reservation_params)
if #reservation.save
redirect_to #save
else
render :new
end
end
private
#add the `days_attributes` to the `reservations_params`
def reservation_params
params.require(:reservation).permit(:passengers, :t_shirt, :hat, days_attributes[:id, name])
end
end
then in new.html.erb when you are creating reservations, you can get a drop down to select specific days. you can do something like:
f.select :days
if you opt to use nested_forms, you'd have to use boostrap_nested_form_for as the documentation suggests.

Resources