Ruby on Rails how to use form input in another method? - ruby-on-rails

I am working on a hotdesking app where the users would check_availability (check_availability.html.erb) of the desks based on the date range chosen and choose from a list of available desk (new.html.erb) before it gets saved in the database.
How can i use the form input in check_availability and use it under my 'new' method?
bookings_controller.rb
class BookingsController < ApplicationController
def index
end
def check_availability
end
def new
#booking = Booking.new(booking_params)
#booking.date_range(params[:book_from], params[:book_to])
end
def create
end
def show
end
private
def booking_params
params.permit(:book_from, :book_to, :wing, :section, :number, :user_id)
end
end
booking.rb
class Booking < ApplicationRecord
belongs_to :user, optional: true
belongs_to :desk, optional: true
accepts_nested_attributes_for :desk, allow_destroy: true
cattr_accessor :current_user
attr_accessor :book_from, :book_to
def check_availability
counter = 0
Booking.all.each do |b|
current_date = Date.today
booked_start_date = b.book_from
booked_end_date = b.book_to
if b.user_id == current_user.id && current_date <= booked_end_date && booked_start_date <= current_date
counter += 1
end
end
puts counter
end
def date_range(book_from, book_to)
a = []
a.push(book_from)
a.push(book_to)
puts a
end
routes.rb
Rails.application.routes.draw do
devise_scope :user do
authenticated :user do
root 'bookings#index', as: :authenticated_root
end
unauthenticated do
root 'devise/sessions#new', as: :unauthenticated_root
end
end
devise_for :users
resources :desks
post '/users/:user_id/bookings/:id', :to => 'bookings#show'
post '/users/:user_id/bookings/new', :to => 'bookings#new'
resources :users do
resources :bookings do
collection do
get :check_availability
end
end
end
end
check_availability.html.erb
<div class="container-fluid">
<div class="row">
<div class='col-sm-6 col-sm-offset-3'>
<h1>Check Availability</h1><hr />
</div>
<div class='col-sm-6 col-sm-offset-3'>
<%= form_tag new_user_booking_path, multipart: true do %>
<div class='form-group'>
<span class='not-bold'><%= label_tag :book_from, "Book From" %>: </span></br>
<span class='date-select'><%= date_select :book_from, class: 'form-control' %></span>
</div>
<div class='form-group'>
<span class='not-bold'><%= label_tag :book_to, "Book To" %>: </span><br />
<span class='date-select'><%= date_select :book_to, class: 'form-control' %></span>
</div>
<%= submit_tag "Check Availability", class: "btn" %>
<% end %>
</div>
<br />
<div class='col-sm-6 col-sm-offset-3'>
<br />
<hr />
<button type="button" class="button">
<%= link_to "My Bookings", authenticated_root_path %>
</button>
<button type="button" class="button">
<%= link_to "Book Desk", new_user_booking_path(current_user) %>
</button>
</div>

It took me lots of tries to figure this out!
I realised it was a routing issue. The form should be doing a GET instead of a PUT request.
I changed the form_tag route in my check_availability.html.erb file to <%= form_tag(new_user_booking_path, method: "get", class: "bookings") do %> and i can now access the form inputs through the controller with params.

Related

Rails 5 - undefined local variable or method `post'

I'm new to Rails. I've created a category model for my posts but when I go to display all posts associated with a particular category I get a NameError page
Here's my categories show.html.erb file:
<h1> <%= "Category: " + #category.name %></h1>
<div align="center">
<%= will_paginate #category_posts %>
</div>
<%= render 'posts/post', obj: #category_posts %>
<div align="center">
<% will_paginate #category_posts %>
</div>
I'm rendering the _post.html.erb partial to display posts that was defined in my post folder.
Looks like the issue is linked to the first line in the code below because the error message points to <li id="post-<%= post.id %>"> in the _post.html.erb code:
<li id="post-<%= post.id %>">
<span class="title"> <%=link_to post.title, post_path(post) %> </span>
<span class="content"><%= truncate(post.content, length: 100) if post.content? %></span>
<span class="content"> <%= image_tag post.picture.url if post.picture? %> </span>
<span class="content">
<% if post.category.any? %>
<p><%= render post.category %></p>
<% end %>
</span>
</li>
And this is my category controller file where I definite the "show" method:
class CategorysController < ApplicationController
before_action :require_admin, except: [:index, :show]
def index
#categories = Category.paginate(page: params[:page])
end
def new
#category = Category.new
end
def create
#category = Category.new(category_params)
if #category.save
flash[:success] = "Category created successfully"
redirect_to categories_path
else
render 'new'
end
end
def show
#category = Category.find(params[:id])
#category_posts = #category.posts.paginate(page: params[:page], per_page: 5)
end
The Post model:
class Post < ApplicationRecord
belongs_to :user
has_many :post_categories
has_many :categories, through: :post_category
default_scope -> { order(created_at: :desc) }
mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :title, presence: true
validate :picture_size
private
# validates the size of an upload picture
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "should be less than 5MB")
end
end
end
The general idea is that when I go to localhost/categories/1 for example, I should have all the posts associated with that category.
Can anyone help me resolve this issue?
You probably mean to render a partial using a collection:
render(partial: 'posts/post', collection: #category_posts)
Where that should expand that partial to repeat once for each post and assign the local post variable.
obj isn't a valid argument, but object is if you want to render the content once with a given object.

Weird Routing Behavior in Rails

I'm using rails 4.2. I have created a form that submits to a particular action in my controller. Here is the beginning of the form code and the controller definition:
view.html.erb
<div id="account-booking" class="tab-pane">
<%= form_for #booking_info, url: { action: 'book' } do |b| %>
<fieldset class="group column-1">
<legend>Booking Preference for <%= Rails.configuration.x.app_settings.year %></legend>
<div class="group column-full radio-list">
<%= label_tag('Select Room Type') %>
<% #available_rooms.each do |rt| %>
<div class="radio-item">
<!--
<%= b.radio_button :room_type_id, rt.id, :class => 'rb_room_type inline', :onclick => fetch_room_info_path(:id => rt.id), :remote => true %>
<%= b.radio_button :room_type_id, rt.id, :class => 'rb_room_type inline', :onclick => 'render_room_info('+ rt.id.to_s + ');' %>
-->
<%= b.radio_button :room_type_id, rt.id, :class => 'rb_room_type inline' %>
<%= content_tag :span, rt.name %>
<a data-toggle="tooltip" data-placement="right" title="<%= rt.description %>">
<%= image_tag "tooltip.png", :class=>"tooltip-icon" %>
</a>
</div>
<% end %>
<%= b.label :roommate_preference, 'Roommate Preference' %>
<%= b.text_area :roommate_preference, :class => 'form-control' %>
<div class="account-checkbox-options">
<%= b.label :is_flexible, class: 'checkbox inline' do %>
<%= b.check_box :is_flexible %>
I am flexible with regards to my room choice.
<% end %>
</div>
</div>
<!--
<div id="estimated-due" class="group column-2">
</div>
-->
</fieldset>
<fieldset class="group column-2 account-preferences">
<legend>Your Room Information for <%= Rails.configuration.x.app_settings.year %></legend>
<div class="group column-1">
<div class="group column-full add-tabbing">
<%= label_tag('Selected Room:') %>
<span><%= #booking_info.room_type.blank? ? '<No Room Selected>' : #booking_info.room_type.name %></span>
</div>
<div class="group column-full add-tabbing">
<%= label_tag('Assigned Room:') %>
<span><%= #booking_info.assigned_type.blank? ? '<No Room Assigned>' : #booking_info.assigned_type.name %></span>
</div>
</div>
<div class="group column-2">
<div class="group column-full add-tabbing">
<%= label_tag('Total Due:') %>
<span ><%= number_to_currency(#booking_info.total_due.blank? ? 0.00 : #booking_info.total_due) %></span>
</div>
<div class="group column-full add-tabbing">
<%= label_tag('Current Balance:') %>
<span><%= number_to_currency(#booking_info.outstanding_balance.blank? ? 0.00 : #booking_info.outstanding_balance) %></span>
</div>
</div>
<% unless #booking_info.assigned_type.blank? %>
<div class="group column-full">
<h2>Assigned Room Information</h2>
</div>
<% end %>
</fieldset>
<div class="account-buttons">
<%= b.submit 'Submit', class: 'btn btn-danger' %>
<%= link_to 'Cancel', '/pages/home', class: 'link-button-cancel' %>
</div>
<% end %>
</div>
account_controller.rb
def book
#booking = PersonRoom.new(booking_params)
#requested_room = RoomType.find(params[:person_room][:room_type_id])
#booking.room_type = #requested_room
if update_booking #booking
redirect_to :controller => 'account', :action => 'view'
else
render('view')
end
end
All of this works beautifully when there is no PersonRoom record (e.g. if I'm doing an insert). However, if I try to update the record, using the same exact form / action (because both the view and the action are exactly the same regardless of whether i'm inserting or updating), I get an error when I click "Submit":
No route matches [PATCH] "/account/book"
This makes no sense. I'm on the exact same page. I just used all of this code to create the record, so the route clearly exists (because it calls /account/book). Now I want to update but suddenly the route doesn't match? And it never even breaks into the code because it doesn't call the controller action. This makes zero sense to me. Hope someone can help.
I winced when looking over your code, here's how I'd have done it:
#config/routes.rb
resources :rooms do
resources :bookings #-> url.com/rooms/:room_id/bookings/new
end
#app/controllers/bookings_controller.rb
class BookingsController < ApplicationController
before_action :set_room
def new
#booking = room.bookings.new
end
def create
#booking = room.bookings.new booking_params
#booking.save
end
def update
#booking = room.bookings.update booking_params
end
private
def set_room
#room = Room.find params[:room_id]
end
def booking_params
params.require(:booking).permit(:x, :y, :z)
end
end
This setup is pretty standard with Rails (IE resourceful routes):
Browsers request pages from Rails by making a request for a URL using
a specific HTTP method, such as GET, POST, PATCH, PUT and DELETE. Each
method is a request to perform an operation on the resource. A
resource route maps a number of related requests to actions in a
single controller.
Observing this principle would likely resolve your "weird" routing errors due to their cohesion with the other aspects of the Rails system.
For example:
#app/controllers/accounts_controller.rb
class AccountsController < ApplicationController
#-> this shouldn't have a "book" action unless necessary. Your case is not necessary
end
--
The problem you have is that you're not adhering to the Rails' convention of keeping your system object-orientated.
The importance of this is huge; Rails is designed to make it as simple as possible to CRUD (create read update destroy) data objects. These objects are built from database data in the "models":
I use this picture a lot - it shows how Rails should work. You build objects in your Models which you manipulate in your controllers. The views show it all to the user.
Thus, when you're looking at your code, I would keep it as simple as possible:
#app/models/room.rb
class Room < ActiveRecord::Base
has_many :bookings
has_many :users, through: :bookings
belongs_to :type
end
#app/models/booking.rb
class Booking < ActiveRecord::Base
belongs_to :room
belongs_to :user
end
#app/models/user.rb
class User < ActiveRecord::Base
has_many :bookings
has_many :rooms, through: :bookings
end
This will allow you to call the following:
#room = Room.find 1
#room.bookings #-> collection of bookings per room
You could also do something like the following (simple) for the views:
#app/views/bookings/new.html.erb
<%= form_for #booking do |f| %>
<%= f.text_field :x %>
<%= f.text_field :y %>
<%= f.text_field :z %>
<%= f.submit %>
<% end %>
I found the problem. It was something really stupid. I had the following line in my route.config:
match ':controller(/:action(/:id))', :via => [:get, :post]
I just needed to change this to:
match ':controller(/:action(/:id))', :via => [:get, :post, :patch, :put, :delete]
Now it handles updates (i.e. patch / put)

Rails ajax form for products

I've been working with app for pizzeria where customers could order pizzas through their website. I currently working with the product page where I try to submit products to shopping cart through ajax, but I'm really stuck. I haven't been able to build a shoppingcart which would accept product-id, product-size-id, extra-toppings as an array and quantity. I decided to try to go with session-store where all the order-row ids are stored and on menu page every product has a form where user could add product, size and quantity to shoppingcart but I keep getting this error in server logs:
Started POST "/order_row" for ::1 at 2015-08-03 11:18:21 +0300
Processing by OrderRowsController#create as JS
Parameters: {"utf8"=>"✓", "order_row"=>{"product"=>"1", "size"=>"0", "quantity"=>"2"}, "commit"=>"Tilaa"}
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms)
ActiveRecord::AssociationTypeMismatch (Product(#70158072501800) expected, got String(#70158039566200)):
app/controllers/order_rows_controller.rb:4:in `create'
I have models Product, ProductCategory, Order, OrderRow and my session stores order-row-ids as mentioned. My menu page is actually product_categories#show -view where products belonging to that category are listed.
#order_rows_controller.rb
class OrderRowsController < ApplicationController
respond_to :html, :js
def create
#orow = OrderRow.new(order_rows_params)
if #orow.save
session[:order_row_ids] << #orow.id
flash[:notice] = "Lisättiin ostoskoriin!"
else
flash[:error] = "Tuotteen lisääminen ostoskoriin epäonnistui."
redirect :back
end
end
def update
#orow = OrderRow.find(params[:id])
if #orow.update_attributes(params[:order_row])
flash[:notice] = "Ostoskori päivitetty."
else
flash[:error] = "Ostoskorin päivitys epäonnistui."
end
end
def destroy
#orow.find(params[:id]).destroy
flash[:notice] = "Tuote poistettu onnistuneesti"
end
private
def order_rows_params
params.require(:order_row).permit(:product, :size, :quantity) #, :extras => []
end
end
ProductCategories-controller
class ProductCategoriesController < ApplicationController
before_action :set_product_category, only: [:edit, :update, :destroy]
respond_to :html, :js
def index
#product_categories = ProductCategory.all
end
def show
#product_category = ProductCategory.friendly.find(params[:id])
#product_categories = ProductCategory.all
#products = #product_category.products
#order_row = OrderRow.new(order: nil, product: nil, size: nil, extras: nil, quantity: nil)
end
And menu-page in product_categories/show.html.erb
#product_categories#show -view
<!--- category descriptions -->
<div class="container">
<% #products.each do |product| %>
<div class="col-sm-6 col-md-4">
<div class="product well">
<h3><%= product.name %></h3>
<span><%= product.description %></span>
<p class="prices">
<%= price(product.normal_price) %> | <%= price(product.plus_size_price) %> | <%= price(product.lunch_price) %>
</p>
<br>
<div id="form-<%= product.id %>">
<%= simple_form_for #order_row, :url => url_for(:controller => 'order_rows', :action => 'create'), remote: true do |f| %>
<%= f.hidden_field :product, :value => product.id %>
<h5>Koko</h5>
<div style="padding-left: 13px">
<%= f.input :size, collection: OrderRow.sizes, as: :radio_buttons, label: false, item_label_class: "radio-inline", item_wrapper_tag: false %>
</div>
<h5>Määrä</h5>
<div style="width: 8%; padding-left: 13px;">
<%= f.input :quantity, as: :string, label: false %>
</div>
<p>
<%= f.submit "Tilaa", class: "btn btn-success btn-lg" %>
</p>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
Create.js.erb in order_rows#create action
#create.js.erb
$("#form-<%= params[:product] %>").load(document.URL + "#form-<%= params[:product]");
Associations:
#order_row
belongs_to :order
belongs_to :product
#product
belongs_to :product_category
has_one :campaign_producte
belongs_to :dish_type
#product_categories
has_many :products
has_many :campaign_products
has_many :product_extras
has_many :dish_types, through: :products
#product_extra
belongs_to :product_category
Link to github-repo: https://github.com/casualCodeAndDesign/ravintolamammamia
What's the reason for this server error and why it doesn't store my order_row to the database?
ActiveRecord::AssociationTypeMismatch (Product(#70158072501800)
expected, got String(#70158039566200))
You need to change
<%= f.hidden_field :product, :value => product.id %>
to
<%= f.hidden_field :product_id, :value => product.id %>
and product to product_id in create.js.erb and order_rows_params

ERB code not rendering in view. Development environment

The views I have created previously are all working fine. I generated a model and controller for subscriptions and have the corresponding views linked to my home page. No error is thrown, but my erb code isn't being rendered to my browser. I can add html (i.e. 'hello world' wrapped in div's).
I've tried the following.
Stripped the surrounding html code and just tried rails helper methods wrapped in erb.
Deleted and re-generated both Subscription model and subscriptions controller/views
Checked my routes.rb file for subscription-related issues
Looked at both of these related questions from SO to no avail. link1
link2
Here is a look at my code and output from webrick:
webrick output
# subscriptions/index.html.erb
<% form_for(#subscription) do |f| %>
<div class="container">
<div class="row-fluid">
<div class="span12">
<div class="widget widget-table">
<div class="widget-header">
<h3>
<i class="icon-"></i> Pay with Credit Card
</h3>
</div>
<div class="widget-content">
<table class="table table-striped table-bordered">
<tbody>
<tr>
<td>
<% if #subscription.stripe_card_token.present? %>
Credit card has been provided.
<% else %>
<div class="control-group">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
</td>
</tr>
<tr>
<td>
<div class="control-group">
<%= label_tag :card_code, "Security Code on Card (CVV)" %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
</td>
</tr>
<tr>
<td>
<div class="control-group">
<%= 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>
</td>
<% end %>
</tr>
<tr>
<td>
<div id="stripe_error">
<noscript><!--Error here--></noscript>
</div>
</td>
</tr>
</tbody>
</table>
</div><!-- END CLASS widget-content -->
</div><!-- END CLASS widget widget-table -->
</div><!-- END CLASS span12 -->
</div><!-- END CLASS row-fluid -->
</div><!-- END CLASS container -->
<% end %>
# routes.rb
Whizcharts::Application.routes.draw do
resources :subscriptions, only: [:new, :create, :index]
# START devise routes
devise_for :admins, controllers: { registrations: "registrations" }# , path_names: { sign_in: "login", sign_out: "logout" }
mount Deviseadmin::Engine, at: "/deviseadmin"
devise_for :users, path_names: { sign_in: "login", sign_out: "logout" }
## END devise routes
# START mailer
# match 'admins/show', to: "admins#show"
## END mailer
# START static_pages routes
root to: "static_pages#home"
match "static_pages/about", to: "static_pages#about", as: :about
match "static_pages/pricing", to: "static_pages#pricing", as: :pricing
match "static_pages/contact", to: "static_pages#contact", as: :contact
## END static_pages routes
# START deployments routes
match "deployments/deployment_print", to: "residents#deployment_print", as: :print
# subscriptions_controller.rb
# Note: Subscription.new is in the index method temporarily to demonstrate this issue
class SubscriptionsController < ApplicationController
def index
#subscription = Subscription.new
#subscriptions = Subscription.all
end
def new
#subscription = Subscription.new
end
def show
#subscription = Subscription.find(params[:id])
end
end
# subscription.rb
class Subscription < ActiveRecord::Base
belongs_to :admin, dependent: :destroy
validates_presence_of :plan_id
attr_accessor :stripe_card_token
def save_with_payment
if valid?
customer = Stripe::Customer.create(plan: plan_id, card: 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
end
# admin.rb
# Note: Included to demonstrate the association between the Admin and Subscription models
class Admin < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :fac_name, :fac_address, :fac_city, :fac_state, :fac_zip, :lic_num, :owner_fname, :owner_lname, :fac_phone1,:fac_phone2, :fac_phone3, :fac_phone4, :fac_phone5, :fac_email1, :fac_email2, :fac_email3, :fac_email4, :fac_email5, :initials
has_many :residents
has_many :fund_record_form2s, through: :residents
has_many :deployments
has_many :subscriptions
def full_name
"#{owner_fname} #{owner_lname}"
end
end
I am running rails 3.2.14
If I forgot something, I will put it up promptly after your notification.
You are missing the equal(=) sign.
It should be <%= form_for(#subscription) do |f| %>
You are missing the equal sign before the form_for helper.
<%= form_for %>
You need the equal sign, otherwise the ERB tags are not put on the template.

Querying multiple linked classes in Rails

I want to query multiple tables. For example in posts table there is a user_id linked to users id. While showing every post, I also want to display the picture of the user. My approach is this, but there is a problem. #user.picture method is undefined.
<% #programs.each do |post| %>
<%= #user = User.where("id = post.user_id") %>
<li class="one-third column">
<div class="wrapper">
<div class="postThumb"><img src="<%= #user.picture %>" /></div>
<div class="postDetails">
<%= link_to "#{ post.title.upcase! }".html_safe, all_posts_path, :class => "postTitle" %>
<p><%= truncate post.details, :length => 90 %></p>
</div>
</div>
</li>
<% end %>
Program Controller:
class ProgramController < ApplicationController
def index
#programs = Program.all
end
User model:
class User < ActiveRecord::Base
attr_accessible :password, :username, :oauth_token, :provider, :uid, :oauth_expires_at, :picture, :email, :name, :location, :gender, :updated_at, :is_admin
has_many :posts
has_one :program
has_many :programdetails, :through => :program
end
Program model:
class Program < ActiveRecord::Base
attr_accessible :details, :title, :user_id
belongs_to :user
has_many :programdetails
end
Try this instead, in the controller:
#programs = Program.includes(:user) # this will return all programs and related users in
# 2 database queries rather than N+1 queries
Then in the view:
<div class="postThumb"><img src="<%= post.user.picture %>" /></div>
Also, you can use image_tag instead.
Finally, you can probably change your post title link to:
<%= link_to post.title.upcase, all_posts_path, :class => "postTitle" %>
#user = post.user. Rails association will give back the associated user by itself.
And to correct above, syntactically, #user = User.find(post.user_id)
try changing this: #user = User.where("id = post.user_id")
into this: #user = User.where(id: post.user_id).first
or even better: #user = post.user as suggested by kiddorails
There is a much easier way to do this using the relations you have already defined:
Programs Controller
def index
#programs = Program.
includes(:user). # eager load user relation to avoid n+1
all
end
View
<% #programs.each do |post| %>
<li class="one-third column">
<div class="wrapper">
<div class="postThumb"><img src="<%= post.user.picture %>" /></div>
<div class="postDetails">
<%= link_to "#{ post.title.upcase! }".html_safe, all_posts_path, :class => "postTitle" %>
<p><%= truncate post.details, :length => 90 %></p>
</div>
</div>
</li>
<% end %>

Resources