Code Optimization in Ruby On Rails? - ruby

I am developing an iOS event application's backend in ROR. Events has privacy either it is public or private and I have made one method to check for the privacy of the event. Currently I run a query which returns 10k records and it is calling that privacy methods 10k times, which is really a time consuming process. What should I do to optimize the code?
Below is the scenario:
def find_events
events = Event.all # It returns 10k records
events.each do |event|
search_for_privacy(event)
end
end
def search_for_privacy event
# Pure Logic
end
Any help would be appreciated.
Thanks

I assume your events table has a column called public or private which indicates whether or not the event is public. You can then easily find all public events by querying like this:
Events.where(public: true)
You can go further an define a scope:
class Event < ActiveRecord::Base
scope :public, -> { where(public: true) }
end
# now you can do:
Event.public
If you do NOT have a column for indicating the privacy settings, but for example derive the privacy from a description, it may be appropriate to evaluate this when saving a record:
class Event < ActiveRecord::Base
before_save :update_privacy
protected
def update_privacy
self.public = self.is_private?
end
def is_private?
# pure logic
end
end
The upside of this is that you only have to process all the steps necessary to determine the privacy once when saving an event, instead of every time a user is searching for public/private events.
(don't forget to add the column in a migration, and in the migration don't forget to set the privacy on EXISTING records)

Related

Have a token/unique url in order to destroy resource

I would like to add following functionality to one of my models:
Once it's created, a token of some sort will be created and this token allows one to destroy the object e.g. http://localhost:3000/items/7AEaC6Nhq946.
Is there a gem or similiar that offers this functionality already?
You could make a 'Tokenable' concern and include it in the models you want to:
In app/models/concerns/tokenable.rb
module Tokenable
extend ActiveSupport::Concern
included do
before_create :generate_token
end
protected
def generate_token
self.random_token = loop do
random_token = SecureRandom.urlsafe_base64(nil, false)
break random_token unless self.class.exists?(random_token: random_token)
end
end
end
In your model:
include Tokenable
Be sure to add the random_token column in the database for the model where you include the concern.
Now in your controller you would do something like Item.find_by(random_token: params[:random_token]) and perform the actions you wish to do with the object.

How to call after_update callback for a particular column updation?

I have one model called points and in that i have 2 columns named clicked_at and opened_at. Those two columns will not be entered while creating record. Both the columns will be updated manually. Now i want to call a callback only for updating clicked_at column. Is there any way to do this? Help will be appreciated.
You have to check it manually.
def my_callback
if clicked_at_changed?
clicked_at_did_change
end
end
def clicked_at_did_change
# do stuff
end
for this ..observers will be a good option and there are many options when you want to call your code..while updating/creating/deleting/editing/saving ...it goes on.
class PointObserver < ActiveRecord::Observer
##this method will be called everytime AFTER you update point object
def after_update(point)
point.clicked_at =Time.now
point.opened_at =Time.now
point.save!
end
end
enable this observer in application.rb
# Activate observers that should always be running.
config.active_record.observers = :point_observer
You can do whatever you want and also you have many callbacks such as before_save,before_update..etc.
Moreover you can place all your observers in app/observers/..

Rails select Empty method?

I have the following select in a helper for my Rails app:
def unit_select
Unit.all.map{|unit| unit.calls.empty? ? [unit.unit_name, unit.id] : ["#{unit.unit_name} (on call)", unit.id] }
end
What this does is look for a unit that has a call and if that unit has a call append (on call) next to the unit in a form. The problem I'm seeing with this is when it goes to look for unit.calls.empty? it's taking into account call records with a status of "closed" which should not be taken into account.
Is there another method I can use (or write) that will allow me to look at unit.calls with passing whether or not the call is in call_status open?
In your Unit model you can override the empty? method on the calls association:
class Unit < ActiveRecord::Base
has_many :calls do
def empty?
self.where(:call_status => :open).any?
end
end
end

How can I guarantee before_destroy callback order in autosave records?

I'm implementing an audit-trail-esque system in my rails3 app; basically, I want to keep track of exactly when my users make any changes.
Currently facing an issue where I have two models - one child to the other. Pseudocode follows:
class Audit;end #this is a straightforward data-storing model, trust me!
class Parent
has_many :children, :dependent => :destroy
before_destroy :audit_destroy
def audit_destroy
Audit.create(:metadata => "some identifying data")
end
end
class Child
belongs_to :parent
before_destroy :audit_destroy
def audit_destroy
Audit.create(:metadata => "some identifying data")
end
end
On calling
Parent.destroy
I'm expecting two new Audit records to be created with created_at timestamps that are ordered relative to the parent records. Said slightly differently: the parent record's Audit is created before the child record's Audit.
This doesn't, however, seem to be guaranteed, as I haven't explicitly said anything about the order of creation of the audit records. While it seems to usually hold true, I have confirmed that sometimes the order of the creation of the Audit records is inverted.
Is there some magic in the depths of ActiveRecord surrounding the ordering of before_destroy callbacks creating new records and autosave?
Thanks,
Isaac

Rails Active Record: Calling Build Method Should Not Save To Database Before Calling Save Method

I have a simple user model
class User < ActiveRecord::Base
has_one :user_profile
end
And a simple user_profile model
class UserProfile < ActiveRecord::Base
belongs_to :user
end
The issue is when I call the following build method, without calling the save method, I end up with a new record in the database (if it passes validation)
class UserProfilesController < ApplicationController
def create
#current_user = login_from_session
#user_profile = current_user.build_user_profile(params[:user_profile])
##user_profile.save (even with this line commented out, it still save a new db record)
redirect_to new_user_profile_path
end
Anyyyyyy one have anyyy idea what's going on.
The definition of this method says the following but it's still saving for me
build_association(attributes = {})
Returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key, but has not yet been saved.
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_one
Ok, I'm sure experienced vets already know this, but as a rookie I had to figure it out the long way...let me see if I can explain this without screwing it up
Although I was not directly saving the user_profile object, I noticed in my logs that something was updating the user model's last_activity_time (and the user_profile model) each time I submitted the form (the user model's last_activity date was also updated when the logged in user did various other things too - I later realized this was set in the Sorcery gem configuration).
Per http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
AutosaveAssociation is a module that takes care of automatically saving associated records when their parent is saved. In my case, the user mode is the parent and the scenario they provide below mirrors my experience.
class Post
has_one :author, :autosave => true
end
post = Post.find(1)
post.title # => "The current global position of migrating ducks"
post.author.name # => "alloy"
post.title = "On the migration of ducks"
post.author.name = "Eloy Duran"
post.save
post.reload
post.title # => "On the migration of ducks"
post.author.name # => "Eloy Duran"
The following resolutions resolved my problem
1. Stopping Sorcery (config setting) from updating the users last_activity_time (for every action)
or
2. Passing an ':autosave => false' option when I set the association in the user model as follows
class User < ActiveRecord::Base
has_one :user_profile, :autosave => false
end

Resources