Rails: how to test if parent has grandchildren present in child model - ruby-on-rails

I (want to) have a method in a parent model (groups) to check if a child (subjects) has children (goals)
groups.rb:
def has_goals?
#answer = []
subjects = self.subjects
subjects.each do |subject|
if subject.try(:goals).present?
#answer << true
else
#answer << false
end
end
if #answer.include?("true")
true
else
false
end
end
I would use this like so -
if group.has_goals?
# do something
else
# do something else
end
at the moment it's not working as it's returning false for everything - whether the subject has goals or not. Any ideas how to get this working?

Check if any of the subjects has at least a goal (subjects.goals should return [] if the subject has no goals):
def has_goals
subjects.any? { |subject| subject.goals.present? }
end
Enumerable#any? reference: http://ruby-doc.org/core-2.0/Enumerable.html#method-i-any-3F

Related

how to write test cases for non crud operations and private method in rspec?

The search method is non-crud action and map is a private method, restaurant, dish, location, pictures are models. these models data contains an array. so how I write test case for map method and search method. restaurant and location has HABTM association, and also restaurant and dish has HABTM association, restaurant and pictures have a polymorphic association, and also dish and pictures has a polymorphic association
def search
map
if params[:name]
#items = Dish.search(params[:name])
end
if params[:price]
#items = Dish.sortby_price(params[:price]).search(params[:name])
end
if params[:ratings]
#items = Dish.sortby_ratings(params[:name])
end
if params[:rating]
#items = Dish.sortby_rating(params[:rating])
end
if params[:category]
#items= Dish.sortby_dietary(params[:category]).search(params[:name])
end
if params[:restaurant]
#restaurants =
Restaurant.find(params[:restaurant])
#items = #restaurants.dishes
end
end
private
def map
#items = Dish.search(params[:name])
restaurants = []
locations = []
pictures = []
#items.each do |d|
#restaurants = d.restaurants
restaurants.push(#restaurants)
d.restaurants.each do |r|
#pictures = r.pictures
pictures.push(#pictures)
#locations = r.locations
locations.push(#locations)
end
end
gon.restaurants = restaurants
gon.locations = locations
gon.pictures = pictures
x = []
#items.each do |d|
#restaurants = d.restaurants
d.restaurants.each do |r|
x.push(r.id)
end
end
y = []
x.each do |x|
r = Restaurant.find(x)
d = r.dishes.count
y.push(d)
end
gon.dishes_count = y
end
Some people say that there is no need to test private methods. But in a company i'm working for we do test private methods.
For your case I'd recommend to do this:
test method #map separately from action #search. You need to check that gon, #items, #restaurants, #pictures, #locations objects got populated correctly.
You can test private methods by using method #send.
Example:
describe '#map' do
subject { controller.send(:map) }
# you would need to stub params method
before { allow(controller).to receive(:params).and_return({ name: 'my name' }) }
it { expect(controller.instance_variable_get(:#items)).to include/not be_blank/... }
end
Test method #search without actually calling method map.
Example:
describe '#search' do
before { allow(controller).to receive(:map) }
# you can set different context where you test cases with different parameters
context 'when params[:name] and params[:ratings] exist' do
before { get :search, { name: '...', ratings: '...' } }
it {...}
end
end

Destroy an object in model file if its missing a condition

How can i destroy this object if its category_attributes(:title) is empty?
def categories_attributes=(categories_attributes)
categories_attributes.values.each do |category_attribute|
category = Category.find_or_create_by(category_attribute)
categories << category
end
end
Try this:
def categories_attributes=(categories_attributes)
categories_attributes.values.each do |category_attribute|
category = Category.find_or_create_by(category_attribute)
if category.title?
categories << category
elsif category.persisted?
category.destroy
end
end
end

How to get object value in ActiveRecord Model?

I want to create custom validation inside The Model.
But nothing in return when i tried to get that value from the variable
This is my model
validate :permanent_event_check
private
def permanent_event_check
param_activity = #activity
# puts "param_activityparam_activityparam_activity"
# puts #activity
# puts param_activity
# puts "param_activityparam_activityparam_activityparam_activity"
if param_activity.permanent == "false"
if param_activity.start_at == "" || param_activity.end_at == ""
#activity.errors[:base] << "You can't leave start and end date blank with Permanent Event"
return false
end
end
end
This is my controller
def create
#activity = admin_current_user.activities.build(activity_param)
if #activity.save
flash[:success] = "Activity Created!"
redirect_to admin_dashboard_url
else
render 'new'
end
end
private
def activity_param
params.require(:activity).permit(:name,:details,:start_at,:end_at,
:activity_image01_url,:activity_image02_url,:activity_image03_url,
:youtube_url,:capacity,:booking_status,:rules,:apply_details,
:payment_price,:payment_need,:avaliable,:rating,:temple_id)
end
But it return nil when i tried to get the value from #activity inside my model.
How can i fix this?
Thanks!
You cannot assign the object like that in the model, instead you van take self.
validates :permanent_event_check
private
def permanent_event_check
if self.permanent == "false"
if self.start_at == "" || self.end_at == ""
self.errors[:base] << "You can't leave start and end date blank with Permanent Event"
return false
end
end
end
I assume that permanent is boolean, start_at and end_at - datetime.
validate :permanent_event_check, unless :permanent
private
def permanent_event_check
# if start_at and end_at are not filled they will be nil which is interpreted as false
unless start_at && end_at
self.errors[:base] << "You can't leave start and end date blank with Permanent Event"
end
end

Accessing model attributes in ActiveSupport::Concern module

I have some models which share the same functionality just on other paths. So I decided to put these methods in a module and set the path in the model. My problem is that I'm not able to access the attribute in my module.
model:
class Job < ActiveRecord::Base
include ImageModel
image_dir = "jobs"
end
module:
module ImageModel
extend ActiveSupport::Concern
def delete_image
unless pic_link == "" || pic_link == nil
begin
if File.delete(Rails.root.join("public", "images", image_dir, pic_link))
return true
else
return false
end
rescue
return true #an error occured but when the image does not exist we still return true
end
end
return true
end
def replace_image(new_image)
File.open(Rails.root.join("public", "images", image_dir, new_image.original_filename), "wb") do |f|
if f.write new_image.read
delete_image
pic_link = new_image.original_filename
return true #everything went fine
else
return false #return false if new image could not be written
end
end
end
end
The error i get:
undefined local variable or method `image_dir' for #<Job:0x007f8a93b9e8d8>
on this line:
File.open(Rails.root.join("public", "images", image_dir, new_image.original_filename), "wb") do |f|
Did I miss something or did I oversee something important?
Felix
I think the design of module still have room to improve. But for this specific question, here is the quickfix.
class Job < ActiveRecord::Base
include ImageModel
def image_dir
"jobs"
end
end
You should define your image_dir = "jobs" in the module itself. because you are including your module in your model, and your module is not able to get the declaration, you have done in your model.
Or you can change your delete_image method to take parameters :
def delete_image(image_dir)
unless pic_link == "" || pic_link == nil
begin
if File.delete(Rails.root.join("public", "images", image_dir, pic_link))
return true
else
return false
end
rescue
return true #an error occured but when the image does not exist we still return true
end
end
return true
end
and where you are calling that method, pass an argument like this:
delete_image("jobs")
same in the case of replace_image method:
def replace_image(new_image, image_dir)
File.open(Rails.root.join("public", "images", image_dir, new_image.original_filename), "wb") do |f|
if f.write new_image.read
delete_image
pic_link = new_image.original_filename
return true #everything went fine
else
return false #return false if new image could not be written
end
end
end
Hope it will help. Thanks

How can I refactor these common controller methods?

I have a few controller methods that are extremely similar and I was wondering what the best way to refactor them would be. First thing that comes to mind would be somehow passing in two blocks to a helper method, but I'm not sure how to do that either.
def action_a
if #last_updated.nil?
#variable_a = #stuff_a
else
#variable_a = (#stuff_a.select{ |item| item.updated_at > #last_updated }
end
end
def action_b
if #last_updated.nil?
#variable_b = #stuff_b.some_method
else
#variable_b = #stuff_b.some_method.select{ |stuff| item.updated_at > #last_updated }
end
end
It just seems like I'm constantly checking if #last_updated is nil (I set the #last_updated instance variable in a before_filter. If I could somehow pass the stuff inside the if as a block and the stuff in the else as another block, then I could remove the if #last_updated.nil? duplication?
What is the best way of accomplishing this for many methods?
Update
Where I specify #stuff_a and #stuff_b, they are always returning an array (since I use .select).
Take a look at this. It's DRYer and should yield identical results.
def action_a
do_the_processing :"#variable_a", #stuff_a
end
def action_b
do_the_processing :"#variable_b", #stuff_b.some_method
end
private
def do_the_processing var_name, collection
if #last_updated.nil?
instance_variable_set var_name, collection
else
instance_variable_set var_name, collection.select{ |item| item.updated_at > #last_updated }
end
end
Update
And here's the two blocks approach (just for fun) (uses 1.9's stabby lambda syntax)
def action_a
check_last_updated is_nil: -> { #variable_a = #stuff_a },
is_not_nil: -> { #variable_a = (#stuff_a.select{ |item| item.updated_at > #last_updated } }
end
def action_b
check_last_updated is_nil: -> { #variable_b = #stuff_b.some_method },
is_not_nil: -> { #variable_b = #stuff_b.some_method.select{ |stuff| item.updated_at > #last_updated } }
end
private
def check_last_updated blocks = {}
if #last_updated.nil?
blocks[:is_nil].try(:call)
else
blocks[:is_not_nil].try(:call)
end
end
You need to extract your condition in a separate def block and use it later on:
def select_updates a
#last_updated.nil? ? a : a.select{ |item| item.updated_at > #last_updated }
end
def action_a; #variable_a = select_updates(#stuff_a) end
def action_b; #variable_b = select_updates(#stuff_b.some_method) end
AS I can see, you could do the followings
have two scope for each
Ex:
class Stuff < ActiveRecord::Base
scope :updated_at, lambda {|updated_date|
{:conditions => "updated_at > #{updated_date}"}
}
end
class Item < ActiveRecord::Base
scope :updated_at, lambda {|updated_date|
{:conditions => "updated_at > #{updated_date}"}
}
end
in your controller do this
def action_a
#variable_a = update_method(#stuff_a)
end
def action_b
#variable_b = update_method(#stuff_b)
end
private
def update_method(obj)
result = nil
if #last_updated.nil?
result = obj.some_method
else
result = obj.some_method.updated_at(#last_updated)
end
result
end
HTH

Resources