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
def maximum_tickets_allowed
(1..maximum_quantity.to_i).to_a
end
end
One of the model methods in Booking.rb is:
class Booking < ActiveRecord::Base
belongs_to :event
belongs_to :ticket
has_many :charges
def check_ticket_count
count = ticket.ticket_quantity.to_i - order_quantity.to_i
ticket.ticket_quantity = count
end
This method is used to print the number of remaining tickets after a successful and it works fine. I would like to know what's the best way to update the total tickets (ticket_quantity field in my table) with this value. I have seen some examples where they do it in controller. What's the Rails way?
I tried using ticket.ticket_quantity.save! and ticket.ticket_quantity.update etc. in the same model method but I encounter errors while doing it. Also, it would be great if you could point me to a resource that explores model methods in depth.
Currently you are not saving the ticket so the update is discarded.
Have you tried
count = ticket.ticket_quantity.to_i - order_quantity.to_i
ticket.update_attribute(:ticket_quantity,count)
update_attribute does not require a save as it auto saves without validations.
Although you should probably validate that the order_quantity is <= ticket_quantity
such as
class Booking < ActiveRecord::Base
...
#just threw this in for you too
after_create :update_ticket_count
validates :order_quantity, numericality:{less_than_or_equal_to: ->(booking){ booking.ticket.ticket_quantity}}
def update_ticket_count
ticket.update_attribute(:ticket_quantity,ticket.ticket_quantity.to_i - self.order_quantity)
end
end
Related
I'm practicing rails and I would like to know how I would validate a situation.
In this case, it's a car rental project. I have a table of Cars (Autos) and one of Unavailable Period.
When registering a car, I assume that the car is available 100% of the month. If someone rents in a certain period, it must be unavailable so it can't be rented again in the same period, how would I do this validation?
Model
class UnavailablePeriod < ApplicationRecord
belongs_to :auto
end
class Auto < ApplicationRecord
belongs_to :rental_company
belongs_to :category
has_many :unavailable_periods
end
Any suggestion? content tip to study this?
What would be the best way?
model
Instead of an UnavailablePeriod I would simply have a Rental model that has a rented_from and a rented_until columns (both datetime).
On creation of a new Rental you then only have to check that there is no existing, date overlapping rental. to check that you could use a custom validation like this:
class Rental < ApplicationRecord
belongs_to :auto
validate :rental_period_is_available
private
def rental_period_is_available
return unless Rental
.where.not(id: id)
.where("rented_from < ? && ? < rented_until", rented_until, rented_from)
.exist?
errors.add(:base, "Car is already booked in this time period")
end
end
I suggest reading about custom validations and validations in general in the offical Rails Guides.
I have the following models:
user.rb
class User < ApplicationRecord
has_many :invitations
end
organization.rb
class Organization < ApplicationRecord
has_many :invitations
end
invitation.rb
class Invitation < ApplicationRecord
belongs_to :user
belongs_to :organization
end
I'm trying to query Active Record in the following way:
user = User.find(params[:id])
user.invitations.includes(:organization)
I want to be able to get all invitations for the user and also have the invitations include attributes of their related organization. However, I am only getting the invitation and none of the organization's attributes.
Even if I try:
Invitation.includes(:organization)
I'm still not getting each invitation's associated organization.
Any and all help is greatly appreciated!
includes method provides eager loading. This solves the N + 1 queries problem. You can access the loaded organization like user.invitations.first.organization. There will be no new queries here.
If you want to combine invitation and organization attributes, you can use joins and select.
user.invitations
.joins(:organization)
.select('invitations.*, organizations.foo, organizations.boo as blabla')
#demir has already answered your question.
Just as an addition - probably, you mixed up includes for models with include option of to_json \ as_json.
If you want to return some JSON result (e.g. in your API response), then you can do user.as_json(include: [invitations: { include: :organization }])
So I'm trying to link two models together
currently, I have tickets for events.
in the event model, I'm under the understanding that one event has one or more tickets so that would be a has many?
and in the tickets table, it would have one event?
In the tickets table, I have the event_id column.
Basically what I've wanting to have is the ability to type event.tickets.each for example to return all the tickets in the event
event.rb model
class Event < ActiveRecord::Base
has_many :tickets
end
ticket.rb model
class Ticket < ActiveRecord::Base
belongs_to :event
end
to fetch tickets of event do like below
event = Event.first
event.tickets.each do |ticket|
puts ticket.inspect
end
in ticket model add has_many :events
in event model add belongs_to :ticket
your events table should have a ticket_id foreign key.
this way you can do event.ticket
and also ticket.events
that is all :)
In many to many fields delete method is deleting all the occurrence of collection. Say I have:
class user < ActiveRecord::Base
has_and_belongs_to_many :cars
end
class car < ActiveRecord::Base
has_and_belongs_to_many :users
end
users and cars are many to many relationship, I have defined my users_cars table. Now user can have repetitive car entry as relation. For example:
Car: A,B,C
User: U1,U2,U3
U1=[A,B,C,A,A,A,B]
Which can be implemented using many to many relationship, the way I have implemented. BUT, at the time when I want to delete one of the car entries of user the problem occurs.
User.cars.delete(car) #deletes all occurrence of car
User.cars.delete_at(User.cars.find_index(video_card)) #delete_at does not exist
Now how to resolve this?
First of all, you can't call User.cars unless you have defined a class level method cars in your User model, but in this way, you would return all cars, and that - in no way - would make sense.
Second, delete_at is a method that works on Array objects, and expects an integer to be passed in. So as a little hack, you can turn your ActiveRecord::Associations object into an array, and then call delete_at method.
user = User.first
user.cars.to_a.delete_at(Car.last.id) # assuming that the last car belongs
# to the first user, something you would never do in actual
# production code.
Edit:
You can also try the following to achieve the same functionality:
user = User.first
user.cars.where("cars.id = ?", Car.first.id).first.delete
Edit 2:
For what you asked in comment, you can have a model for the table cars_users.
rails g model CarUser
class Car < ActiveRecord::Base
has_many :cars_users
has_many :users, through: car_users
end
class User < ActiveRecord::Base
has_many :cars_users
has_many :cars, through: car_users
end
class CarUser < ActiveRecord::Base
belongs_to :car
belongs_to :user
end
And now, you can do:
CarUser.where("car_id = ? AND user_id = ?", Car.first.id, User.first.id).first.delete
Booking -< Orders -< Transactions
class Booking < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :booking
has_many :transactions
end
class Transaction < ActiveRecord::Base
belongs_to :order
end
I need to be able to create a Transaction without an Order or Booking existing.
I'm trying to achieve the following:
When a Transaction is created an Order and a Booking is automatically created. The transaction form can take a Booking.booking_number which will be saved to the above automatically created Booking.
I'm very new to rails and have tried a combination of accepts_nested_attributes_for, Ryan Bates' nested model form part1 screencast and form_fields_for without success.
Some guidance, not necessarily code, would be much appreciated.
My routes look like:
I need to be able to create a Transaction without an Order or Booking
existing.
Bad system design - surely a transaction would follow an order or booking?
From your question, I'd highly recommend creating a booking or order first. This will allow you to create a transaction as a bolt-on to the order or booking:
#app/controllers/bookings_controller.rb
Class BookingsController < ApplicationController
def create
booking = Booking.new(booking_params)
booking.save
end
end
#app/models/booking.rb
Class Booking < ActiveRecord::Base
before_create :build_transaction #-> creates a blank transaction which can be populated later
end
Nonetheless, there's nothing stopping you creating a transaction & assigning an order later
You can do this:
#app/controllers/transactions_controller.rb
def create
Transaction.new(transaction_params)
end
#app/models/transaction.rb
Class Transaction < ActiveRecord::Base
after_create :order
def order
self.order.create!([order_details?])
end
end
If you tell me some more about what you're building, I'll be able to create a more refined response!
Try this it may be work.
In your model
accepts_nested_attributes_for :order, :allow_destroy => true
change whether true/false depending on your form