Add new record to a new record - ruby-on-rails

I'm using rails 4.1.6
I have a problem creating new records and then saving them. Here are the models:
class Function < ActiveRecord::Base
belongs_to :theater
has_many :showtimes, dependent: :destroy
belongs_to :parsed_show
validates :theater, presence: :true
validates :date, presence: :true
end
class Theater < ActiveRecord::Base
has_many :functions, :dependent => :destroy
validates :name, :presence => :true
accepts_nested_attributes_for :functions
end
class Showtime < ActiveRecord::Base
belongs_to :function
validates :time, presence: true
validates :function, presence: true
end
showtime = Showtime.new time: Time.current
theater = Theater.first # read a Theater from the database
function = Function.new theater: theater, date: Date.current
function.showtimes << showtime
function.showtimes.count # => 0
why is the showtime not being added to the function's showtimes? I need to save the function later with the showtimes with it.

Your Function object hasn't been persisted. You need to make sure that it's persisted (which of course also requires that it be valid) before you can add things to its list of showtimes.
Try saving the function beorehand, and if it succeeds (that is if function.persisted? is true), it should allow you to << directly into function.showtimes, as you like. Alternatively, you can use the Function#create class method instead of the Function#new class method, since the former automatically persists the record.

You can use Function#create
theater = Theater.first # read a Theater from the database
function = Function.new theater: theater, date: Date.current
function.showtimes.create(time: Time.current)

I forgot to check if saving the function also saved the theaters, and even though function.showtimes.count returns 0, the showtimes are saved to the database anyway.
function.showtimes.count returns:
=> 0
but
function.showtimes returns:
=> #<ActiveRecord::Associations::CollectionProxy [#<Showtime id: nil, time: "2015-01-09 04:46:50", function_id: nil>]>

Related

Is there an easy way to remove blank objects from a has-many association?

I got the following models:
class Course < ApplicationRecord
has_many :external_ids, as: :identifiable, dependent: :destroy, validate: true
accepts_nested_attributes_for :external_ids
end
and this one:
class ExternalId < ApplicationRecord
belongs_to :identifiable, polymorphic: true
validates :name, presence: true, uniqueness: true
validates :identifiable, presence: true, on: :create
end
Because of a nested form in the course form-view it's possible that a blank object of an external id will be saved. I'd like to remove these blank objects. With "blank object" I mean an ExternalId which is a new record and has a blank name. Currently I do that as follows:
#course.attributes = course_params
## SNIP - workaround to fix validations
external_ids = []
#course.external_ids.each do |ext_id|
external_ids << ext_id unless(ext_id.new_record? && ext_id.name.blank?)
end
#course.external_ids = external_ids
## SNAP - workaround to fix validations
#course.save
But this is a lot of code for a very simple task. Is there any function for that? destroy_if doesn't exists for an association, only for arrays.
Thanks you!
You can use accepts_nested_attributes_for with such key
accepts_nested_attributes_for :external_ids, reject_if: proc { |attributes| attributes['name'].blank? }
From docs:
You may also set a :reject_if proc to silently ignore any new record hashes if they fail to pass your criteria

Make query with association and search by custom model method rails

I have this problem, i tried to get all Beauty Salons when the service has a promotion, but service has a custom method and return true or false, this is the structure of my code
class BeautySalon < ActiveRecord::Base
has_many :services
end
class Service < ActiveRecord::Base
belongs_to :beauty_salon
has_many :service_promotions
has_many :promotions, through: :service_promotions
def has_promotion?
## consult another tables and return true or false if found a promotion
end
end
iam tried to make the query like this
BeautySalon.all.includes(:services).select('services.*').select{|service| service.has_promotion?}
but rails return this error
NoMethodError (undefined method `has_promotion?' for #BeautySalon:0x0055a1119d1f40)
Any advice for this?
UPDATE
the method has_promotion do this
def has_promotion?
if promotions.exists?
if get_promotions(Date.today).exists?
return true
else
return false
end
end
return false
end
def get_promotions(date)
if promotions.exists?
promotions.where('start_date <= ? and end_date >= ?',date,date)
end
end
and another tables are there
class Promotion < ActiveRecord::Base
validates :discount, presence: true
validates :start_date, presence: true
validates :end_date, presence: true
has_many :service_promotions
has_many :services, through: :service_promotions
end
class ServicePromotion < ActiveRecord::Base
validates :service_id, presence:true
validates :promotion_id, presence:true
belongs_to :service
belongs_to :promotion
end
thanks for all the advises
BeautySalon.joins(:services).select { |beauty_salon| beauty_salon.services.any?(&:has_promotion?) }
This is an option. You are now calling has_promotion? on the wrong object (e.g. beauty salon instead of service) and the error is raised because the instance method is defined in Service.rb.
It would be better in my opinion to add a database column has_promotion (boolean) to your services table.
BeautySalon.joins(:services).where(has_promotion: true)
If has_promotion? simply retrieves data from another associated model (other_association, with db boolean column promotion) you can also do something like this:
BeautySalon.joins(services: other_association).where(other_association: { promotion: true })
Update:
BeautySalon.joins(services: :promotions).where("promotions.start_date <= :date AND promotions.end_date >= :date", date: Date.current )
This will return all beauty salons with running service promotions (today).

Rails validation callback just once

I'm trying to figure out how can I validate a model just once.
Here is the situation:
It's about a library management
class Loan < ActiveRecord::Base
attr_accessible :book_id, :check_in, :check_out, :member_id
belongs_to :book
belongs_to :member
validates :member_id, :presence => true
validates :book_id, :presence => true
validate :returned_book, :on => :update
def returned_book
self.book.update_attributes! quantity: self.book.quantity + 1
self.book.update_attributes! borrowed_count: self.book.borrowed_count - 1
end
end
What i would like to do, is when i put a check_out date (i'm returning a book):
Increment the quantity of the book
Decrement the borrowed_count of the book
But just once, not every time I update the record or change the check_out date
Im my code here, every time I save (update) the record the validation runs...
Validations should be used to validate things, not modify state. A callback would be more appropriate in this case. Maybe something like:
attr_accessor :quantities_adjusted
before_save :update_quantities
def update_quantities
if changed_attributes.keys.include?('check_out') && !quantities_adjusted
self.book.quantity += 1
self.book.borrowed_count -= 1
self.quantities_adjusted = true
end
end

How to validate that a dependent row belongs to a user

I have a model called Category;
class Category < ActiveRecord::Base
belongs_to :user
belongs_to :group
validates :name, presence: true
validates :user_id, presence: true
end
And, I have a model called Group:
class Group < ActiveRecord::Base
belongs_to :user
has_many :categories
validates :name, presence: true
validates :user_id, presence: true
end
As you can see, a group can have many categories. When a user adds a category or updates it's group_id value, I want to check that the group belongs to that user. I don't want users adding to and update categories to another user's group. What is best practise to validate this prior to saving? Thanks
validate :ownership_of_group
def ownership_of_group
ids = []
ids << self.group_id
ids << self.group_id_was if self.group_id_was.present?
if(Group.find(ids).reject {|group| group.user_id == self.user_id}.present?)
# if all of them is owned by the user the array will return an empty array
errors.add(:user_id, 'You cant edit a category that is not yours')
end
end
If we say group_id we get the current value that is being set by the use.
If we say group_id_was it get the old value before the update.
In the update we need to handle both in the create we have no previous value.

Validate whether foreign key exists if not nil

I have a many-to-one relationship defined in Rails 4:
class Event < ActiveRecord::Base
belongs_to :user
end
How do I check, that the :user key exists if it is set?
The following correctly checks, that the key exists but does not allow for `nil? values:
validates :user, presence: true
The following allows any value, even non-existing IDs:
validates :user, presence: true, allow_nil: true
How do you do such kind of validation.
You can use the before_save callback to check that the user is valid if it is supplied:
class Event < ActiveRecord::Base
belongs_to :user
before_save: :validate_user unless: Proc.new { |event| event.user.nil? }
private
def validate_user
if User.where(id: user_id).empty?
errors[:user] << "must be valid"
end
end
end
You must keep the presence validation in Event and add in User model:
has_many :events, inverse_of: :user
Just faced this problem and here are the 2 solutions
1.
validates :user, presence: true, if: 'user_id.present?'
2.
. https://github.com/perfectline/validates_existence gem
can be used like this
validates : user, existence: { allow_nil: true, both: false }
both option is for the error messages: false will show 1 error(association only), true will show 2 errors (association and foreign key)

Resources