ruby on rails about form_for - ruby-on-rails

Hi I want to create an ec site and try to make quantity system.
What I want to do: Adding a item in quantity of CreateBasketItems(2021_create_basket_items.rb)
Question: How can I write some code in item/show.html.erb which is part of form_with() in particular?
2021_create_basket_items.rb
class CreateBasketItems < ActiveRecord::Migration[5.2]
def change
create_table :basket_items do |t|
t.references :basket, index: true, null: false, foreign_key: true
t.references :item, index: true, null: false, foreign_key: true
t.integer :quantity, null: false, default: 1
t.timestamps
end
end
end
item/show.html.erb
The url: show.html.erb => item_controller.rb/create
<%= form_for url: item_add_to_baskets_path(#item,#basket_item), method: :post do |f| %>
  <%= f.select :quantity,[1,2,3], id: "country1", class: "frm-field required sect" %>
<%= f.submit "add to basket", class: "item_add" %>
<% end %>
just in case the error is.
ArgumentError (wrong number of arguments (given 1, expected 0)):
item_controller.rb
class ItemsController < ApplicationController
# before_action :authenticate_user!
def show
basket = current_user.prepare_basket
#item = Item.find(params[:id])
#basket_item = basket.basket_items(params[:quantity])
end
def index
# if(params[:category])
# #items = Item.where(category: params[:category]).paginate(page: params[:page])
# else
# #items = Item.paginate(page: params[:page])
# end
#items = (params[:category]) ? Item.where(category: params[:category]).paginate(page: params[:page]) :
Item.paginate(page: params[:page])
end
end
add_to_basket_controller.rb
class Items::AddToBasketsController < Items::ApplicationController
def create
basket = current_user.prepare_basket
#item = Item.find(params[:item_id])
#basket_item = basket.basket_items(params[:quantity])
basket.basket_items.create!(item_id: #item.id, quantity: #basket_item)
flash[:success] = "your item in basket"
redirect_to baskets_path
end
end

There are a couple of issues with the code.
basket.basket_items doesn't expect any arguments but you're passing one. In fact, you don't need that line of code at all. Remove it.
You're not passing the right quantity to the create! call.
basket.basket_items.create!(item_id: #item.id, quantity: params[:quantity])

Related

Validation Error * Checkin time must be a valid current or future time - ruby on rails

I'm running into an issue with my rails build. I've created a hotel application and when trying to check out a room at any future time or date it gives me an error described in the picture below. I'm open to any feedback and your help is sincerely appreciated! I've attached a screenshot of the issue and all my code that I can think of that might be related.
PICTURE OF THE PROBLEM
reservation.rb
class Reservation < ActiveRecord::Base
belongs_to :user
belongs_to :room
attr_accessor :checkin_date, :checkin_time, :checkout_date, :checkout_time
validates_presence_of :checkin_date
validates_presence_of :checkin_time
validates_presence_of :checkout_date
validates_presence_of :checkout_time
validates_presence_of :number_of_rooms
validate :future_checkin_date
validate :future_checkin_time
validate :future_checkout_date
validate :future_checkout_time
validate :no_of_rooms_greater_then_0, if: lambda { number_of_rooms.present? }
def future_checkin_date
if checkin_date.present? && checkin_date.to_date < DateTime.now.to_date
errors.add(:checkin_date, 'must be a valid current or future date')
end
end
def future_checkin_time
if checkin_time.present? && checkin_time.to_time < Time.now
errors.add(:checkin_time, 'must be a valid current or future time')
end
end
def future_checkout_date
if checkin_date.present? && checkout_date.present? &&
checkout_date.to_date < checkin_date.to_date
errors.add(:checkout_date, 'must be a valid date after your check in ' \
'date')
end
end
def future_checkout_time
if checkin_datetime.present? && checkout_datetime.present? &&
checkout_datetime <= checkin_datetime
errors.add(:checkout_time, 'must be a valid time after your check in ' \
'time.')
end
end
def no_of_rooms_greater_then_0
errors.add(:number_of_rooms, 'must be 1 or more to make a reservation') if
number_of_rooms <= 0
end
def convert_to_datetime
if self.checkin_date.present? && self.checkin_time.present?
self.checkin_datetime = self.merge_datetime(
self.checkin_date,
self.checkin_time
)
end
if self.checkout_date.present? && self.checkout_time.present?
self.checkout_datetime = self.merge_datetime(
self.checkout_date,
self.checkout_time
)
end
end
def merge_datetime(date1, time1)
res_date = Date.parse(date1)
res_time = Time.parse(time1)
merged_datetime = DateTime.new(
res_date.year,
res_date.month,
res_date.day,
res_time.hour,
res_time.min,
res_time.sec
)
end
def room_name
room.room_type.name
end
def decrease_room_inventory
room.update(inventory: (room.inventory -= number_of_rooms))
end
def self.default_checkin_date
DateTime.now.strftime('%Y-%m-%d')
end
def self.default_checkin_time
(DateTime.now.midday + 3.hours).strftime('%H:%M')
end
def self.default_checkout_date
DateTime.now.tomorrow.strftime('%Y-%m-%d')
end
def self.default_checkout_time
(DateTime.tomorrow.midday).strftime('%H:%M')
end
def self.users_reservations(user)
where('user_id = ?', user)
end
def reservation_date(booking_datetime)
booking_datetime.strftime('%Y-%m-%d')
end
def reservation_time(booking_datetime)
booking_datetime.strftime('%H:%M')
end
def self.reservations_checkin_setter(reservations)
reservations.each do |reservation|
reservation.checkin_date = reservation.reservation_date(
reservation.checkin_datetime
)
reservation.checkin_time = reservation.reservation_time(
reservation.checkin_datetime
)
end
end
def self.reservations_checkout_setter(reservations)
reservations.each do |reservation|
reservation.checkout_date = reservation.reservation_date(
reservation.checkout_datetime
)
reservation.checkout_time = reservation.reservation_time(
reservation.checkout_datetime
)
end
end
def hotel_name
room.hotel.name
end
def increase_room_inventory
room.update(inventory: (room.inventory += number_of_rooms))
end
def self.reservation_checkin_setter(reservation)
reservation.checkin_date = reservation.reservation_date(
reservation.checkin_datetime
)
reservation.checkin_time = reservation.reservation_time(
reservation.checkin_datetime
)
end
def self.reservation_checkout_setter(reservation)
reservation.checkout_date = reservation.reservation_date(
reservation.checkout_datetime
)
reservation.checkout_time = reservation.reservation_time(
reservation.checkout_datetime
)
end
def alter_room_inventory(orginal_number)
if number_of_rooms != orginal_number.to_i
room = Room.find(room_id)
room.update(inventory: (room.inventory += orginal_number.to_i))
answer = self.room_available?(room.room_type)
if answer[0]
self.decrease_room_inventory
else
room.update(inventory: (room.inventory -= orginal_number.to_i))
end
answer
else
false
end
end
def room_available?(room_type)
if Room.find(room_id).inventory == 0
message = "Unfortunately, all of those #{room_type.name} rooms have "\
"been reserved. Please select another room"
return false, message
elsif number_of_rooms > Room.find(room_id).inventory
message = "Unfortunately, your desired quantity of the " \
"#{room_type.name} room is not available. Please select another " \
"room, or reserve less rooms of this type"
return false, message
else
[true]
end
end
def user_view_reservation_date(booking_datetime)
booking_datetime.to_date.strftime('%A, %B %d, %Y')
end
def user_view_reservation_time(booking_datetime)
booking_datetime.to_time.strftime('%l:%M %P')
end
def total_nights
(checkout_datetime.to_date - checkin_datetime.to_date).to_i
end
def total_price
nights = self.total_nights == 0? 1 : self.total_nights
cost = nights * room.room_rate * number_of_rooms
taxes = cost * 0.15
cost + taxes
end
end
_reservation.html.erb
<div>
<h3><%= reservation.room_name %> at <%= reservation.hotel_name %></h3>
<ul>
<strong>Check In: </strong>
<%= reservation.user_view_reservation_time(reservation.checkin_time) %> on
<%= reservation.user_view_reservation_date(reservation.checkin_date) %>
<br />
<strong>Check out: </strong>
<%= reservation.user_view_reservation_time(reservation.checkout_time) %> on
<%= reservation.user_view_reservation_date(reservation.checkout_date) %>
<br />
<strong>Rooms: </strong>
<%= reservation.number_of_rooms %><br />
</ul>
<h3>Your Rate</h3>
<ul>
<strong>Total Nights: </strong>
<%= reservation.total_nights %><br />
<strong>Average Nightly Rate: </strong>
<%= number_to_currency(reservation.room.room_rate) %><br />
<strong>Estimated Total Price: </strong>
<%= number_to_currency(reservation.total_price) %><br />
</ul>
<%= button_to 'Edit',
edit_reservation_path(reservation, reservation.id), method: 'get',
class: 'btn btn-large btn-primary' %><br />
<%= button_to 'Delete', reservation_path(reservation), method: 'delete',
data: { confirm: 'Are you sure you want to delete this reservation?' },
class: 'btn btn-large'%>
</div>
reservations_controller.rb
class ReservationsController < ApplicationController
before_action :require_login
before_action :set_reservation, only: [:edit, :update, :destroy]
def index
#reservations = Reservation.users_reservations(current_user)
Reservation.reservations_checkin_setter(#reservations)
Reservation.reservations_checkout_setter(#reservations)
end
def create
#reservation = Reservation.new(reservation_params)
#reservation.checkin_date=(reservation_params[:checkin_date])
#reservation.checkin_time=(reservation_params[:checkin_time])
#reservation.checkout_date=(reservation_params[:checkout_date])
#reservation.checkout_time=(reservation_params[:checkout_time])
#reservation.convert_to_datetime
#room_type = RoomType.find(params[:reservation][:room_type_id])
result = #reservation.room_available?(#room_type)
if result[0]
if #reservation.save
#reservation.decrease_room_inventory
redirect_to reservations_path,{notice: "Your reservation " \
"for the #{#reservation.room_name} has been made, $0 are due today"}
else
render :'room_types/show'
end
else
redirect_to room_path(#reservation.room.hotel),
{alert: "#{result[1]}"}
end
end
def edit
if #reservation.user_id == current_user.id
Reservation.reservation_checkin_setter(#reservation)
Reservation.reservation_checkout_setter(#reservation)
render :edit
else
flash[:alert] = "You don't have permission to edit that reservation."
redirect_to reservations_path
end
end
def update
#reservation.checkin_date=(reservation_params[:checkin_date])
#reservation.checkin_time=(reservation_params[:checkin_time])
#reservation.checkout_date=(reservation_params[:checkout_date])
#reservation.checkout_time=(reservation_params[:checkout_time])
#reservation.convert_to_datetime
#reservation.number_of_rooms = reservation_params[:number_of_rooms]
result = #reservation.alter_room_inventory(
params[:reservation][:orginal_number_of_rooms]
)
if !result || result[0]
if #reservation.save
redirect_to reservations_path,{notice: "Your reservation " \
"for the #{#reservation.room_name} has been updated."}
else
render :edit
end
else
redirect_to reservations_path, {alert: "#{result[1]}"}
end
end
def destroy
#reservation.increase_room_inventory
#reservation.delete
redirect_to reservations_path,{notice: "Your reservation for " \
"#{#reservation.checkin_datetime.strftime('%A, %B %d, %Y')} has " \
"been deleted."}
end
private
def set_reservation
#reservation = Reservation.find_by(id: params[:id])
end
def reservation_params
params.require(:reservation).permit(
:checkin_date,
:checkin_time,
:checkout_date,
:checkout_time,
:number_of_rooms,
:room_id,
:user_id
)
end
end
user.rb
class User < ActiveRecord::Base
has_many :reservations, dependent: :destroy
has_many :rooms, through: :reservations
has_many :addresses, dependent: :destroy
validates_presence_of :name
has_secure_password
validates_associated :addresses, unless:
Proc.new { |user| user.provider.present?}
def addresses_attributes=(addresses_attributes)
addresses_attributes.values.each do |address_attributes|
if address_attributes.keys.include?('id')
address = self.addresses.find(address_attributes[:id])
address.update_attributes(address_attributes)
else
self.addresses.build(address_attributes)
end
end
end
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.password = SecureRandom.hex
end
end
def update_room_inventory
reservations.each do |reservation|
reservation.increase_room_inventory
end
end
end
routes.rb
Rails.application.routes.draw do
get '/auth/:provider/callback', to: 'sessions#github'
resources :addresses, only: [:new, :create, :destroy]
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
resources :reservations, only: [:index, :edit, :update, :destroy]
resources :rooms, only: :show do
resources :room_types, only: :show
resources :reservations, only: :create
end
root 'hotels#index'
end
create_reservations.rb
class CreateReservations < ActiveRecord::Migration
def change
create_table :reservations do |t|
t.references :room, index: true, foreign_key: true
t.references :user, index: true, foreign_key: true
t.integer :number_of_rooms, default: 1
t.datetime :checkin_datetime
t.datetime :checkout_datetime
t.timestamps null: false
end
end
end
I see that the error is from
def future_checkin_time as the error message says
Checkin time must be a valid current or future time
Also as per your code in the error message checkin time value must be shown. Can you please print and check if the value is being captured properly?

Update a status field comparing dates after an action

this is the schema and my model for Visit (visit's status can be: Confirmed, Current, Expired and To be approved)
schema.rb
create_table "visits", force: true do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.date "start"
t.date "end"
t.integer "idVisit"
t.integer "employee_id"
t.integer "visitor_id"
t.string "status", default: "Confirmed"
end
Visit.rb
class Visit < ActiveRecord::Base
belongs_to :employee
belongs_to :visitor
default_scope -> { order(:created_at) }
validates :start, presence: true, uniqueness: {scope: [:end, :visitor_id]}
validates :end, presence: true
validates :visitor_id, presence: true
validates :employee_id, presence: true
validate :valid_date_range_required
def valid_date_range_required
if (start && end) && (end < start)
errors.add(:end, "must be after start")
end
end
end
Now my problem is that I need to compare for each visit, after each time I do show action in employees_controller.rb, the start and end date to Date.today (except for To be approved status); according to it I will change the status of visits in the database.
Here is what I did but probably there will be some mistakes since for now an error occurs at least, so I hope you could help me to fix it.
In Visit.rb I created this:
def check_visit_status(visit)
if visit.status != 'To be confirmed'
if visit.start <= Date.today && visit.end >= Date.today
visit.status = 'Current'
end
if visit.end < Date.today
visit.status = 'Expired'
end
end
end
Now in employees_controller.rb I have (I won't post it all):
class EmployeesController < ApplicationController
after_action :update_status, only: :show
def show
if logged_in?
#employee = Employee.find(params[:id])
#indirizzimac = current_employee.indirizzimacs.new
#visitor = current_employee.visitors.new
#visit = current_employee.visits.new
#visits = current_employee.visits.all
if params[:act]=='myData'
render 'myData'
elsif params[:act]=='myNetwork'
render 'myNetwork'
elsif params[:act]=='temporaryUsers'
render 'temporaryUsers'
elsif params[:act]=='guestsVisits'
render 'guestsVisits'
elsif params[:act]=='myAccount'
render 'myAccount'
else
render 'show'
end
else
render 'static_pages/errorPage'
end
end
def update_status
if #visits.any?
#visits.each do |visit|
check_visit_status(visit)
end
end
end
end
Thank you a lot in advance
I really have to thank eeeeeean for his immense help.
I figured out my problem so I want to post here my solution in order to help someone looking for the same thing I was asking for.
employees_controller.rb
class EmployeesController < ApplicationController
after_action :update_status, only: :show
def show
[...]
end
def update_status
if #visits.any?
#visits.each do |visit|
visit.check_visit_status
end
end
end
end
Visit.rb
def check_visit_status
if self.status != 'To be confirmed'
if self.start <= Date.today && self.end >= Date.today
self.update_attribute :status, 'Current'
end
if self.end < Date.today
self.update_attribute :status, 'Expired'
end
end
end
You need to call check_visit_status on an instance of Visit, but right now it's being called on self, which in this scope refers to the employees controller. Try this:
visit.rb
def check_visit_status
if self.status != 'To be confirmed'
if self.start <= Date.today && end >= Date.today
self.status = 'Current'
end
if self.end < Date.today
self.status = 'Expired'
end
end
end
Then call it like this:
employees_controller.rb
#visits.each do |visit|
visit.check_visit_status
end
That should get you out of that particular error.

Unknown attribute in Rails - creating new Object

I'm working on my Rails API. Currently I want to save an Object through post-requests from my Device. The requests are working fine, but there is a problem saving it to the DB. Rails says:
ActiveRecord::UnknownAttributeError (unknown attribute 'idea_id' for IdeaTag.):
app/controllers/data_controller.rb:42:in `update_ideas'
So, I know this means it can't find the attribute "idea_id" in "IdeaTag".
Heres my data_controller.rb
class DataController < ApplicationController
skip_before_filter :verify_authenticity_token
def token
name=params[:owner]
password=params[:password]
#owner = Owner.authenticate_by_name(name, password)
if #owner
if #owner.user_uuid.blank?
#user = User.new
#user.token = SecureRandom.uuid
#user.name = #owner.name
#user.owner_uuid = #owner.uuid
#user.created_at = Time.now
#user.updated_at = Time.now
#user.isLoggedIn = false
#user.save!
end
#user = User.find_by_uuid(#owner.user_uuid)
if #user.token.blank?
token = SecureRandom.uuid
#user.token = token
#user.save
end
else
render nothing: true, status: :unauthorized
end
end
def update_ideas
uuid = params[:uuid]
text = params[:text]
title = params[:title]
owner_uuid = params[:owner_uuid]
tag_id_1 = params[:tag_id_1]
tag_id_2 = params[:tag_id_2]
tag_id_3 = params[:tag_id_3]
tag_id_4 = params[:tag_id_4]
updated_at = params[:timeStamp]
#idea = Idea.new(:uuid => uuid, :text => text, :title => title, :owner_uuid => owner_uuid, :tag_ids => [tag_id_1, tag_id_2, tag_id_3, tag_id_4], :updated_at => updated_at)
#idea.save!
render json: {:status => 200}
end
def getjson
token = params[:token]
#user = User.find_by_token(token)
#users = User.all
#owner = Owner.find_by_user_uuid(#user.uuid)
#Owners = Owner.all
ownerUuid = #owner.uuid
#tags=Tag.all
#ideas=Idea.where(:owner_uuid => ownerUuid)
#votes=Vote.all
#votings=Voting.all
end
# def token_auth
# token = params[:token]
# #owner = Owner.find_by_token(token)
# if #owner
# update_ideas
# end
# end
end
the error happens in method "update_ideas" the following line
#idea = Idea.new(:uuid => uuid, :text => te...
Idea Model:
class Idea < ActiveRecord::Base
self.primary_key = :uuid
has_many :idea_tags
has_many :tags, through: :idea_tags
belongs_to :voting
has_many :votes
belongs_to :owner
end
Idea migration file
class CreateIdeas < ActiveRecord::Migration
def change
create_table :ideas, :id => false, :primary_key => :uuid do |i|
i.string :uuid
i.string :title
i.string :text
i.string :owner_uuid
i.string :voting_uuid
i.datetime :created_at
i.datetime :updated_at
end
end
end
How do i save Objects like this proper?
Since you are using uuid as primary key for ideas, I'm guessing you have idea_uuid field in IdeaTag? If yes, you need to add foreign_key: 'idea_uuid to has_many :idea_tags, otherwise it will by default assume foreign_key is idea_id . You might have to add it to belongs_to methods as well.
has_many :idea_tags, foreign_key: 'idea_uuid'
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

NoMethodError undefined method `id' for nil:NilClass:

I know this kind of question is already answered multiple times but i seriously unable to figure it out what is causing a problem here, I am having trouble solving this problem. I keep getting the same error when i'm trying to create new registration ( http://localhost:3000/registrations/new?course_id=1 ) :
NoMethodError at /registrations
undefined method `id' for nil:NilClass
Here is my RegistrationsController:
class RegistrationsController < ApplicationController
before_action :set_registration, only: [:show, :edit, :update, :destroy]
def index
#registrations = Registration.all
end
def show
end
def new
#registration = Registration.new
#course = Course.new
#course = Course.find_by id: params["course_id"]
end
def create
#registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
raise "Please Check Registration Errors" unless #registration.valid?
#registration.process_payment
#registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
rescue Exception => e
flash[:error] = e.message
render :new
end
protect_from_forgery except: :webhook
def webhook
event = Stripe::Event.retrieve(params["id"])
case event.type
when "invoice.payment_succeeded" #renew subscription
Registration.find_by_customer_id(event.data.object.customer).renew
end
render status: :ok, json: "success"
end
private
def stripe_params
params.permit :stripeEmail, :stripeToken
end
def set_registration
#registration = Registration.find(params[:id])
end
def registration_params
params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token)
end
end
My Registration Model:
class Registration < ActiveRecord::Base
belongs_to :course
def process_payment
customer_data = {email: email, card: card_token}.merge((course.plan.blank?)? {}: {plan: course.plan})
customer = Stripe::Customer.create customer_data
Stripe::Charge.create customer: customer.id,
amount: course.price * 100,
description: course.name,
currency: 'usd'
#Annotate Customer Id when Registration is Created
cusotmer_id = customer.id
end
def renew
update_attibute :end_date, Date.today + 1.month
end
end
Registration New.html.haml File :
%section#course-content
%section#ruby
%section.detailed-syllabus
.wrapper-inside
= form_for #registration, html: { class: "basic-grey" } do |f|
- if #registration.errors.any?
#error_explanation
%h2
= pluralize(#registration.errors.count, "error")
prohibited this registration from being saved:
%ul
- #registration.errors.full_messages.each do |message|
%li= message
.field
= f.hidden_field :course_id, value: #course.id
.field
= f.label :full_name
= f.text_field :full_name
.field
= f.label :company
= f.text_field :company
.field
= f.label :email
= f.text_field :email
.field
= f.label :telephone
= f.text_field :telephone
//‘Stripe.js’ will recognize the card data because we have marked the inputs with ‘data-stripe’ attribute as: number, cvv, exp-month and exp-year.
= javascript_include_tag "https://js.stripe.com/v2/"
:javascript
Stripe.setPublishableKey('#{Rails.application.secrets.stripe_publishable_key}');
= label_tag "Card Number", nil, required: true
.control-group
.controls
= text_field_tag :card_number, nil, class: "input-block-level", "data-stripe" => "number"
= label_tag "Card Verification", nil, required: true
.control-group
.controls
= text_field_tag :card_verification, nil, class: "input-block-level", "data-stripe" => "cvv"
= label_tag "Card Expires", nil, required: true
= select_tag :exp_month, options_for_select(Date::MONTHNAMES.compact.each_with_index.map { |name,i| ["#{i+1} - #{name}", i+1] }), include_blank: false, "data-stripe" => "exp-month", class: "span2"
= select_tag :exp_year, options_for_select((Date.today.year..(Date.today.year+10)).to_a), include_blank: false, "data-stripe" => "exp-year", class: "span1"
.actions
= f.submit "Registration Payment", class: "btn", style: "color: white;background: rgb(242, 118, 73);"
Does anyone know how to assist me in this? Greatly appreciate all the help.
Additional Can anyone please guide me through how to pass id between 2 models like this guy did between 2 models as he's creating a scaffold for one model but passing ID lets him create values for another model too without creating actions for another controller https://github.com/gotealeaf/stripe-basics.git
Edited:
GitHub Repository For This Code
https://github.com/ChiragArya/Stripe_CheckOut_Demo
From your comments, it appears the error is caused by :
#course.id being nil
The way to fix this is to ensure #course is defined properly. You need to do the following:
def new
#registration = Registration.new
#course = Course.find_by id: params["course_id"]
end
The other issue you have here is that your routes should be able to handle courses without having to append them with ?course_id=1:
#config/routes.rb
resources :registrations do
get :course_id, to: "registrations#new" #-> yoururl.com/registrations/:course_id
end
This will still give you the course_id param in the new action; just makes it more Rails.
--
Controller
You also need some structure in your code (you're aiming for fat model, thin controller). It looks like you're coming to Rails as a Ruby dev; you need to appreciate that Rails handles most of the exceptions etc for you.
Specifically, you need to look at how to remove code out of your actions:
def create
#registration = Registration.new registration_params
#registration.process_payment
if #registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
else
# handle error here
end
end
private
def registration_params
params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token).merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
end
-
`id' for nil:NilClass
Finally, you have to remember this error basically means the variable you're trying to invoke an action for is nil.
Ruby populates nil variables with a NilClass object, thus it's difficult to determine what the error actually is. All it means is that the variable you're trying to call a method on doesn't have the aforementioned method, as Ruby has populated it with the NilClass object.
Try changing Registration#new action to
def new
#course = Course.find(params[:course_id])
#registration = #course.registrations.new
end
add this in your def create
def create
#course = Course.find_by id: params["registration"]["course_id"]
#registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
raise "Please Check Registration Errors" unless #registration.valid?
#registration.process_payment
#registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
rescue Exception => e
flash[:error] = e.message
#course = Course.find_by id: params["registration"]["course_id"]
render :new
end

NoMethodError in Lines#show

UPDATE: The answer bellow is correct. Just wanted to update what I did to solve the problem.
First I had to delete all my previous lines in the rails console.
Then I used the bye bug gem in my lines controller at the bottom of the create method to discover where the next bug occurred. I created a test line that I needed to delete again. so I ran
Line.last.delete in console.
This is the way my lines controller create method looks now (working no bugs)
def create
if user_signed_in?
#line = Line.create(line_params)
if #line
if params[:line][:previous_line_id].empty?
#line.story = Story.create
#line.save
else
#line.story = #line.previous_line.story
#line.save
end
redirect_to line_path(#line)
else
flash[:error] = #line.errors
redirect_to line_path(Line.find(params[:line][:previous_line_id]))
end
else
Finally I ran #Lines.each { |line| line.update.attribute(:story_id: 3)}
This gave the necessary association between lines and story.
ORIGINAL POST BELLOW.
I'm getting this error in my rails app. I think that when I create a new line or start a story, it doesn't automatically add it to a story object. I've listed my show.html.erb file as well as my lines controller.rb file.
What am I missing? How do I get the controller to add data to the story object correctly?
Thanks!
I added a few lines of code to my lines controller:
class LinesController < ApplicationController
def new
params[:previous_line_id].nil? ? #line = Line.new : #line = Line.find(params[:previous_line_id]).next_lines.create
#lines = #line.collect_lines
#ajax = true if params[:ajax]
render :layout => false if params[:ajax]
if #line.previous_line
#line.update_attribute(:story_id, #line.previous_line.story.id)
else
story = Story.create
#line.story = story
#line.save
end
end
def create
if user_signed_in?
#line = Line.create(line_params)
if #line
redirect_to line_path(#line)
else
flash[:error] = #line.errors
redirect_to line_path(Line.find(params[:line][:previous_line_id]))
end
else
flash[:error] = "Please sign in or register before creating a line!"
unless params[:line][:previous_line_id].empty?
redirect_to line_path(Line.find(params[:line][:previous_line_id]))
else
redirect_to root_path
end
end
end
# params[:id] should correspond to the first line of the story.
# if params[:deeper_line_id] is not nil, that means that they want to render up to the nested line id
def show
#lines = Line.find(params[:id]).collect_lines
#next_lines = #lines.last.next_lines.ranked
#lines.last.update_attribute(:score, #lines.last.score + 1)
end
def select_next
#line = Line.find(params[:id])
#line.update_attribute(:score, #line.score + 1)
#lines = [#line]
#next_lines = #line.next_lines.ranked
render :layout => false
end
def send_invite
if user_signed_in?
UserInvite.send_invite_email(current_user,Line.find(params[:id]), params[:email]).deliver
flash[:notice] = "Your invite was sent!"
else
flash[:error] = "Please sign in"
end
redirect_to Line.find(params[:id])
end
private
def line_params
params.require(:line).permit(:text, :previous_line_id, :user_id)
end
end
I added these lines to the controller pictured above
if #line.previous_line
#line.update_attribute(:story_id, #line.previous_line.story.id)
else
story = Story.create
#line.story = story
#line.save
end
Here is my show.html.erb file
<div class="row">
<div class="col-lg-2">
</div>
<div class="box-container col-lg-7 ">
<div id="story" class="box">
<% #lines.each do |line| %>
<span class="story-line" data-id="<%=line.id%>"><%= link_to line.text, '#', :class=>"story-line" %></span>
<% end %>
</div>
<div id="next-steps">
<%= render 'next_steps' %>
</div>
<span style="font-size:.9em; margin-bottom:15px; display:block;">*If the links don't work, try refreshing.</span>
</div>
<div class="col-lg-2" style="padding-right:25px;">
<%= render 'invite' %>
Your Fellow Collaborators: <br />
<div class="collaborators">
<% #lines.last.story.collaborators.uniq.each do |collaborator| %>
<%= link_to profile_path(:id => collaborator.id) do %>
<%= image_tag collaborator.profile_image_uri, :class => "prof-icon" %>
<% end %>
<% end %>
</div>
Story model
class Story < ActiveRecord::Base
has_many :lines
has_and_belongs_to_many :collaborators, :class_name => "User", :join_table => "collaborators_stories", :association_foreign_key => :collaborator_id
def first_line
self.lines.first_lines.first_lines.first
end
end
Here is my lines.rb file
class Line < ActiveRecord::Base
scope :first_lines, -> { where previous_line_id: nil}
scope :ranked, -> { order("score + depth DESC")}
belongs_to :user
belongs_to :story
belongs_to :previous_line, :class_name => "Line", :foreign_key => "previous_line_id"
has_many :next_lines, :class_name => "Line", :foreign_key => "previous_line_id"
validates_presence_of :text
after_create :update_depths
def update_depths
line = self.previous_line
while !line.nil?
line.update_attribute(:depth, line.depth + 1)
line = line.previous_line
end
end
def first_line
line = self
while !line.previous_line.nil?
line = line.previous_line
end
line
end
def collect_lines
line = self
lines = [self]
while !line.previous_line.nil?
lines.unshift(line.previous_line)
line = line.previous_line
end
lines
end
end
Problem is orphaned lines in your database. Look for them and associate it to a story, or delete it:
How to find orphaned records:
http://antonzolotov.com/2013/01/26/how-to-find-and-delete-orphaned-records-with-ruby-on-rails.html
Then review the create method to ensure a line should be part of a story:
#short example review activerecord relations
#story = Story.find(params[:story_id])
story.lines.create(line_params)
That should work.
EDIT:
def self.find_orphan_ids
Lines.where([ "user_id NOT IN (?) OR story_id NOT IN (?)", User.pluck("id"), Story.pluck("id") ]).destroy_all
end

Resources