Unable to make after_create to work - ruby-on-rails

I'm creating a ticket booking app for my sample project using Ruby on Rails 4.1. Three are three models - Events, Tickets and Bookings. Events have many tickets and bookings. Tickets have many bookings and they belong to events. Bookings belongs to events and tickets.
Here's the ticket model:
class Ticket < ActiveRecord::Base
belongs_to :event
has_many :bookings
belongs_to :user
validates :ticket_name, :terms_conditions, presence: true
validates_date :booking_start_date, on: :create, on_or_after: :today
validates_date :booking_end_date, after: :booking_start_date
validates :ticket_price, presence: true, numericality: true
validates :ticket_quantity, :minimum_quantity, :maximum_quantity, presence: true, numericality: { only_integer: true }
before_create :check_start_date
before_update :check_start_date
def check_start_date
if (self.booking_start_date >= DateTime.now) && (self.booking_end_date != DateTime.now)
self.status = 'Open'
else
self.status = 'Closed'
end
end
def maximum_tickets_allowed
(1..maximum_quantity.to_i).to_a
end
end
The bookings model:
class Booking < ActiveRecord::Base
belongs_to :event
belongs_to :ticket
has_many :charges
validates :buyer_name, presence: true
validates :order_quantity, presence: true, numericality: { only_integer: true }
validates :email, presence: true, format: { with: /\A[^#\s]+#([^#.\s]+\.)+[^#.\s]+\z/ }
def total_amount
ticket.ticket_price.to_i * order_quantity.to_i
end
def check_ticket_count
count = ticket.ticket_quantity.to_i - order_quantity.to_i
ticket.update_attribute(:ticket_quantity, count)
end
end
The bookings controller:
class BookingsController < ApplicationController
before_action :authenticate_user!, only: [:index, :destroy]
def index
#event = Event.find(params[:event_id])
##bookings = #event.bookings.all
#bookings = #event.bookings.paginate(page: params[:page], per_page: 10)
end
def new
#event = Event.find(params[:event_id])
#ticket = #event.tickets.find(params[:ticket_id])
#booking = Booking.new
end
def create
#event = Event.find(params[:event_id])
#ticket = #event.tickets.find(params[:ticket_id])
#booking = #event.bookings.create(booking_params)
#booking.ticket = #ticket
Stripe.api_key = Rails.configuration.stripe[:secret_key]
#token = params[:stripeToken]
#amount = #booking.total_amount
begin
customer = Stripe::Customer.create(
:email => #booking.email,
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:currency => "usd",
#:card => token
)
flash[:notice] = "Thanks for the order"
rescue Stripe::CardError => e
flash[:danger] = e.message
end
if #booking.save
BookingMailer.booking_confirmation_user(#booking).deliver
flash[:notice] = "You've successfully booked the tickets!"
redirect_to [#event, #booking]
else
render 'new'
end
end
def show
#event = Event.find(params[:event_id])
#booking = #event.bookings.find(params[:id])
end
def destroy
#event = Event.find(params[:event_id])
#booking = #event.bookings.find(params[:id])
#booking.destroy
redirect_to event_bookings_path
end
private
def booking_params
params.require(:booking).permit(:buyer_name, :email, :mobile, :address, :order_quantity, :ticket_id)
end
end
The check_ticket_count method in Booking.rb works fine as long as I don't an add after_create :check_ticket_count method. The moment I add that after_create method, the app throws the "undefined method `ticket_quantity' for nil:NilClass" error. How to get past this?

Looks like you should first associate ticket with booking, and only then create booking.
#booking = #event.bookings.new(booking_params)
#booking.ticket = #ticket
#booking.save
Hopefully you will ask questions with less code next time.

Related

NoMethodError at /charges undefined method `coupons' for nil:NilClass When creating coupon instance

please i am trying to create coupons for a particular ticket in my charges controller after a user has made payment but i keep getting this error; NoMethodError at /charges
undefined method `coupons' for nil:NilClass. Any help? Below is my code;
Ticket Model
class Ticket < ApplicationRecord
belongs_to :event
has_many :order_items, dependent: :destroy
has_many :coupons, dependent: :destroy
before_save :set_ticket_sku
def ticket_sku
self.sku = SecureRandom.hex
end
private
def set_ticket_sku
self[:sku] = ticket_sku
end
end
Coupon Model
class Coupon < ApplicationRecord
belongs_to :ticket
before_save :set_code
def generate_code
self.code = SecureRandom.hex
end
private
def set_code
self[:code] = generate_code
end
end
Charges Controller
class ChargesController < ApplicationController
skip_after_action :verify_authorized
before_action :authenticate_user!
def new
end
def create
#order = current_order
#order_items = #order.order_items.last
#amount = #order.subtotal_in_cents
#ticket = Ticket.find_by(sku: params[:sku])
#quantity = #order_items.quantity
customer = Stripe::Customer.create({
email: params['stripeEmail'],
source: params['stripeToken']
})
charge = Stripe::Charge.create({
customer: customer.id,
amount: #amount,
description: "Event Payment",
currency: 'usd'
})
#quantity.times do
#ticket.coupons.create!
end
redirect_to root_path
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
In charges controller Params[:sku] is nil

Undefined method `keys' for nil:NilClass after include Paperclip

Im new in ruby on rails and after I included papperclip i get this error if i try to change photo.
If I change create method like in a README.md on paperclip`s github:
def create
#hotel = Hotel.create( hotel_params )
end
private
# Use strong_parameters for attribute whitelisting
# Be sure to update your create() and update() controller methods.
def hotel_params
params.require(:hotel).permit(:name, :photo, :room_description, :price_for_room, :breakfast, :country, :state, :city, :street)
end
I get the same error in Create method. Could you help me? What am I missing here?
Ruby 1.9.3
Rails 4
Paperclip 4.2.0
Error screenshot
hotels_controller.rb
class HotelsController < ApplicationController
before_action :signed_in_user, except: [:index, :show]
def index
#hotels = Hotel.paginate(:page => params[:page], :per_page => 5)
end
def show
#hotel = Hotel.find(params[:id])
#comments = #hotel.comments
end
def new
#hotel = Hotel.new
end
def edit
#hotel = Hotel.find(params[:id])
end
def create
#hotel = current_user.hotels.new(params[:hotel])
if #hotel.save
redirect_to #hotel, notice: "Hotel was successfully created."
else
render "new"
end
end
def update
#hotel = Hotel.find(params[:id])
if #hotel.update_attributes(params[:hotel])
redirect_to #hotel, notice: "Hotel was successfully updated."
else
render "edit"
end
end
def destroy
#hotel = Hotel.find(params[:id])
#hotel.destroy
redirect_to hotels_url
end
end
hotel.rb
class Hotel < ActiveRecord::Base
has_many :comments
belongs_to :user
has_many :ratings
has_many :raters, :through => :ratings, :source => :users
validates :name, presence: true, length: { minimum: 5 }
validates :room_description, presence: true
validates :price_for_room, presence: true, numericality: true
validates_associated :comments
has_attached_file :photo, :styles => { :medium => "500x500>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :photo, :content_type => /\Aimage\/.*\Z/
def update_average_rating
#value = 0
self.ratings.each do |rating|
#value = #value + rating.value
end
#total = self.ratings.size
update_attributes(average_rating: #value.to_f / #total.to_f)
end
end
As you are using Rails4, your update action should be like this
def update
#hotel = Hotel.find(params[:id])
if #hotel.update_attributes(hotel_params) #Here
redirect_to #hotel, notice: "Hotel was successfully updated."
else
render "edit"
end
end

How do i sort by date?

am new to rails, I have a rails app that allows me to create a deadline by providing a title, date and description and it creates a countdown, the problem is I want to sort all the deadlines by the date entered, how do i do that in my index method?
class DeadlinesController < ApplicationController
def new
#deadline = current_user.deadlines.new
end
def create
#deadline = current_user.deadlines.new(params[:deadline].permit(:title, :date, :description))
if #deadline.save
redirect_to #deadline
else
render 'new'
end
end
def show
#deadline = Deadline.find(params[:id])
end
def edit
#deadline = current_user.deadlines.find(params[:id])
end
def index
#deadlines = current_user.deadlines.all
#deadlines = current_user.deadlines.paginate(:page => params[:page], :per_page => 5)
end
def update
#deadline = current_user.deadlines.find(params[:id])
if #deadline.update(params[:deadline].permit(:title, :date, :description))
redirect_to #deadline
else
render 'edit'
end
end
def destroy
#deadline = current_user.deadlines.find(params[:id])
#deadline.destroy
redirect_to deadlines_path
end
private
def post_params
params.require(:deadline).permit(:title, :date, :description)
end
end
deadlines model:
class Deadline < ActiveRecord::Base
validates :title, presence: true,
length: { minimum: 8 }
validates :date, presence: true
validates :description, presence: true,
length: { maximum: 230 }
#validates_format_of :date, :with => /\A[0-9]{4}-[0-1][0-9]-[0-3][0-9]\z/, :message => "Enter Date in this format: YYYY-MM-DD"
belongs_to :user
end
#deadlines = current_user.deadlines.order(:date)
.paginate(:page => params[:page], :per_page => 5)
You can use the order method
#deadlines = current_user.deadlines.order(:date)
You can also specify ascending or descending using,
#deadlines = current_user.deadlines.order(date: :asc) # Ascending
#deadlines = current_user.deadlines.order(date: :desc) # Descending

undefined method `unread_messages' in controller

I am working on the unread folder for my inbox messaging system. I received a undefined method `unread_messages' when going to /users/1/messages?mailbox=unread and it's pointing to the messages controller. However I have unread_messages defined in the user.rb so that it shows unread messages in the inbox, so I'm assuming the code should also work for the unread folder. Any help would be appreciated.
user.rb:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :role, :age, :age_end, :password_confirmation, :about_me, :feet, :inches, :password, :birthday, :career, :children, :education, :email, :ethnicity, :gender, :height, :name, :password_digest, :politics, :religion, :sexuality, :user_drink, :user_smoke, :username, :zip_code
validates_uniqueness_of :email
validates_format_of :email, with: /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_presence_of :password, :on => :create
has_many :galleries
has_many :photos, :through => :galleries
before_create { generate_token(:auth_token) }
ROLES = %w[admin user guest banned]
# models/user.rb
after_create :setup_gallery
def received_messages
Message.received_by(self)
end
def unread_messages?
unread_message_count > 0 ? true : false
end
def sent_messages
Message.sent_by(self)
end
# Returns the number of unread messages for this user
def unread_message_count
eval 'messages.count(:conditions => ["recipient_id = ? AND read_at IS NULL", self.user_id])'
end
def to_s; username
end
def has_role?(role_name)
role.present? && role.to_sym == role_name.to_sym
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
private
def setup_gallery
self.galleries << Gallery.create
end
end
messages_controller:
def index
if params[:mailbox] == "sent"
#messages = #user.sent_messages
elsif params[:mailbox] == "inbox"
#messages = #user.received_messages
#elsif params[:mailbox] == "archieved"
# #messages = #user.archived_messages
end
if params[:mailbox] == "unread"
#messages = #user.unread_messages
end
end
def new
#message = Message.new
if params[:reply_to]
#reply_to = User.find_by_user_id(params[:reply_to])
unless #reply_to.nil?
#message.recipient_id = #reply_to.user_id
end
end
end
def create
#message = Message.new(params[:message])
#message.sender_id = #user.id
if #message.save
flash[:notice] = "Message has been sent"
redirect_to user_messages_path(current_user, :mailbox=>:inbox)
else
render :action => :new
end
end
def show
#message = Message.find(params[:id])
#message.readingmessage if #message.recipient == current_user
end
def destroy
#message = Message.find(params[:id])
#message.destroy
flash[:notice] = "Successfully deleted message."
redirect_to user_messages_path(#user, #messages)
end
def delete_multiple
if params[:delete]
params[:delete].each { |id|
#message = Message.find(id)
#message.mark_message_deleted(#message.id,#user.id) unless #message.nil?
}
flash[:notice] = "Messages deleted"
end
redirect_to user_messages_path(#user, #messages)
end
private
def set_user
#user = current_user
end
end
message.rb:
attr_accessible :subject, :body, :sender_id, :recipient_id, :read_at,:sender_deleted,:recipient_deleted
validates_presence_of :subject, :message => "Please enter message title"
belongs_to :sender,
:class_name => 'User',
:foreign_key => 'sender_id'
belongs_to :recipient,
:class_name => 'User',
:foreign_key => 'recipient_id'
# marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.
# When both sender and recipient marks it deleted, it is destroyed.
def mark_message_deleted(id,user_id)
self.sender_deleted = true if self.sender_id == user_id
self.recipient_deleted = true if self.recipient_id == user_id
(self.sender_deleted && self.recipient_deleted) ? self.destroy : self.save!
end
# Read message and if it is read by recipient then mark it is read
def readingmessage
self.read_at ||= Time.now
save
end
# Based on if a message has been read by it's recipient returns true or false.
def read?
self.read_at.nil? ? false : true
end
def self.received_by(user)
where(:recipient_id => user.id)
end
def self.not_recipient_deleted
where("recipient_deleted = ?", false)
end
def self.sent_by(user)
Message.where(:sender_id => user.id)
end
end
First of all, you've defined unread_messages? method, not unread_messages
Secondly, you should not use ? : in unread_messages? method:
unread_messages_count > 0
is enough.
You should define unread_messages method in your User model. I can't show the inner code in this method because I don't know your models relations.
You defined
unread_messages? # note the question mark
Then referred to it as
#user.unread_messages # no question mark
You probably want a method
def unread_messages ## which holds the actual unread messages and does not return boolean

How to create 3 objects using one form only if they are valid?

I want to create Job, Employer and Company using one form.
How to create a Job only if Job, Company and Employer are valid?
Model
class Job < ActiveRecord::Base
accepts_nested_attributes_for :company, :employer
belongs_to :company
belongs_to :employer
validates :employer_id, presence: true, on: :update
validates :company_id, presence: true
def self.initialize_with_company(job_params)
company_attributes = job_params.delete(:company_attributes)
job_params.delete(:employer_attributes)
new(job_params) do |job|
job.company = Company.find_or_create_by_nip(company_attributes)
end
end
def create_employer(employer_attributes)
self.employer = Employer.create(employer_attributes)
end
end
Controller
class JobsController < ApplicationController
def new
#job = Job.new
if current_employer
#job.company = current_employer.companies.first
else
#job.company = Company.new
end
#job.employer = current_employer || Employer.new
end
def create
employer_attributes = params[:job][:employer_attributes]
#job = Job.initialize_with_company(params[:job])
if current_employer
#job.employer = current_employer
else
#job.create_employer(employer_attributes)
end
if #job.save
if current_employer
redirect_to dashboard_path
else
redirect_to jobs_path
end
else
render 'new'
end
end
end
View
= simple_form_for #job do |f|
...
= f.simple_fields_for :company do |c|
...
= f.simple_fields_for :employer do |e|
...
= f.button :submit
You can use the ActiveRecord validates_associated method thusly:
validates_associated :employer
validates_associated :company
Be aware, it is possible to create a recursive loop of dependent models if you do validates_associated :job in one of the other models. Avoid this.

Resources