Main menu

Tag Archives: Ruby on Rails

Post navigation

At my current job, we use mongodb as our main database and as you can imagine we query our database a lot. The followings are what I found while investigating some slow performance. Hopefully it will prevent you from making the same mistake or pinpoint the source of problem quickly. We are using Rails 4 with Mongoid.

1. Don’t use regular expression with /i in queries.

One of the offending query looked pretty innocent. Customer is embedded document with email attribute and email field is indexed.

So, why the difference? I couldn’t quite figure it out myself. I knew that Mongodb uses B-Tree for index and index for email was already created. What about the regular expression was making it slow? I thought perhaps the anchor tags (\A and \z) were causing it, but that wasn’t it. I tried using substring of email and anchoring the beginning of email string (using ^), but that didn’t yield difference either.

I finally turned to Stack Overflow for assistance, and within a few minutes, someone provided exact answer I was looking for. They key to the answer was in output of explain method.

Look at the nscanned and indexBounds in the output of explain method for the first method. It scanned all index because the upper and lower bounds are not defined ("" and {}).

Compare that to the output of explain method for the second method. Exactly the same upper and lower bounds, and it only scanned extremely small number of objects. This explains the big performance difference between the two methods.

That’s pretty reasonable performance. So, it must be something in the addition of two collections. When you add two collections using Mongoid, it returns an array, so it might be something related to converting to an array. Let’s check the performance on that.

Ah-ha! Looks like we found the problem. Converting to an array is quite slow. In order to use single collection, without converting to an array, I created a parent class – ProductParent, and ProductA and ProductB would inherit from that class. In such way, one collection is used and subclasses are distinguished by just type field. Actually, it should have been parent/subclass structure since ProductA and ProductB are kinds of a Product, and both share many of the same attributes.

Since it’s using the application layout, you will see the error message you specify in the layout. The following is my 500 error page, /views/errors/internal_server_error.html.haml. For 404 page, you can also use @not_found_path instance variable in the view as well.

#errors-page
.thumbnail.errors
.errors-500
.caption
%h5 Sorry
%h1 500 Internal Server Error
- # Do not remove this line. It is used for development
- # purposes. When an error is found. In development, it
- # shows the logs, in production it is nil.
.error-msg
= @log

Twilio created cloud telephony services made mainly for developers. I’ve been meaning to figure out how to use their service, and I had a chance to develop a Ruby on Rails app using Twilio app called Phonein. You can check out the source code here. It’s nothing fancy, and totally not optimized. I also used Twitter’s Bootstrap CSS/JS package.

While Twilio had a few samples for Ruby on Rails, it was kind of outdated and a few things were incorrect. I wanted to share what I did to use Twilio API to help you come up to speed quickly.

Basically my app is for home-care professionals, and it allows them to check in and out using client’s phone. For Twilio, the followings are its requirements.

Identify client by phone number

Identify home-care professional by 6-digit identification code

Check in the home-care professional at the client’s location

Read out tasks for the home-care professional

Check out the home-care professional from the client’s location

Twilio has its own markup language called TwiML, and in Twilio controller I created, TwiML is used to create views (or voices). I also created certain POST actions under Twilio controller that will receive input from phone (digits punched in by a person) and use it to look up information.

1. Answer incoming call

When you sign up with Twilio, you can configure destination URL Twilio will invoke when it receives an incoming call. For mine, it would be “http://phonein.herokuapp.com/twilios/incoming”. So, I have “incoming” action defined in “Twilios” controller.

Controller in app/controller/twilios_controller.rb

Just like a regular Ruby on Rails app, controller gets objects ready for the view. It looks up client using the incoming phone number. If client is not found, it says (instead of displaying) an error message and hangs up. If client is found, it asks user to enter a 6-digit code. @post_to object contains URL that will be invoked after user interacts with Twilio. In our case, it’s after user enters code.

xml.instruct!
xml.Response do
xml.Say "Client could not be found."
xml.Hangup
end

2. Verifies home-care professional, checks in, and reads tasks.

Next, look up the home-care professional by the 6-digit code. The numbers user punched will be in ‘Digits’ parameter. If user is found but has not checked in before, it checks in the user and gives some options. If user has already checked in before, user is presented with a few options including an option to check out.

3. Read tasks, check out or hear about Yang

In addition to incoming and verify actions.

This is where main messages are configured and played. Depending on the option user chooses, it will either 1) say the tasks again, 2) check the user out, 3) say a few things about Yang, or 4) just hang up.

This is an update to my last post about Facebook Connect with a Rails app. At the time I was using facebooker plugin (yeah, a plugin, not a gem), which has been discontinued for the longest time, and thus wouldn’t work with current Facebook connect.

Since then, I’ve used omniauth, omniauth-facebook, and devise gems to implement Facebook connect with a few Rails app I have been toying with. So, this is kind of an update to my last post about integrating Facebook Connect with a Rails app.

1. First, you need the following gems in your Gemfile.

gem 'devise'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'oauth2'

Make sure you install them by running “bundle install” command.

2. Next configure devise gem.

rails generate devise:install

3. Apply devise to a model. 99.9% of time, this would be the User model.

rails generate devise User

4. Next, generate authentication model with the following columns. Token column is extra, if you want to save an access token.

5. Configure omniauth by modifying config/initializers/omniauth.rb

Rails.application.config.middleware.use OmniAuth::Builder do
# The following is for facebook
provider :facebook, [APP ID], [SECRET KEY], {:scope => 'email, read_stream, read_friendlists, friends_likes, friends_status, offline_access'}
# If you want to also configure for additional login services, they would be configured here.
end

6. After user authenticates with whatever provider you specify, user needs to be redirected to omniauth call, so add the following line in your routes.rb.

match '/auth/:provider/callback' => 'authentications#create'

7. Then in Authentications controller, you figure out whether to create a new user or log the user in, if the user is an existing user. For complete hash, take a look at omniauth-facebook github page.

def apply_omniauth(auth)
# In previous omniauth, 'user_info' was used in place of 'raw_info'
self.email = auth['extra']['raw_info']['email']
# Again, saving token is optional. If you haven't created the column in authentications table, this will fail
authentications.build(:provider => auth['provider'], :uid => auth['uid'], :token => auth['credentials']['token'])
end

9. In Authenication model,

belongs_to :user

10. In your view, user clicking on /auth/facebook/ link will be redirected to Facebook to log in.

11. This method doesn’t do FB login in a popup. For that, you have to use FB Javascript SDK, and you can use the example here.

Most people need to do this only when they get a new system. I had to go through this to help out a potential brogrammer, and it would have been much easier if I pointed him to one place where he could just following direction. Instruction here applies to Mac OS X 10.6.x.

1. Install Xcode

Xcode is included in the Mac OS X install disc. You can install from the DVD or you can down load it from here, http://developer.apple.com/xcode/. If you already have xcode installed, you are good to go.

2. Install Git

Download and install git if you don’t have one already. Do the following and see if returns a version.

git --version

Best place is to go here (http://git-scm.com/), and download and install the latest stable release.

3. Install RVM and Ruby

RVM lets you manage set of gems for Ruby/Rails version combination. This is the best way to install Ruby and Rails. Follow the link below and install RVM and Ruby version 1.9.2 (which is latest, stable version as of this time).

4.2 Unzip and Install

tar xzvf rubygems-1.X.Y.tgz
cd rubygems-1.X.Y
sudo ruby setup.rb

5. Configure RVM gemset

Now, you have to actually make a choice whether you want to install the latest version 3.1 or the one before 3.0.x. If you just do gem install rails, it will install 3.1. I am sticking with 3.0.10 for a little longer, since that’s what I am used to. But, if you are starting new, you should just install 3.1. When you search for code examples online, make sure it’s for 3.1, since 3.1 is quite different from 3.0.x.

rvm gemset create rails31

Also set default gemset.

rvm use 1.9.2@rails31 --default

6. Install Rails

Depending on what you decided above,

gem install rails -v 3.1.0

7. Install Postgresql 8.x

I’ve used MySQL mostly before, but after Oracle’s purchase of MySQL and since I deploy most of my apps on Heroku, which only supports Postgresql, I have been using Postgresql for quite sometime. For typical Rails app, it shouldn’t matter whether you use MySQL or Postgresql. You need to be careful when you need to write raw SQL statement. Postgresql is known to be more strict with the syntax.

Latest Postgresql is 9.x, but I believe pg gem only supports up to 8.x. Better stick with safe version. Follow the link below to download and install Postgresql 8.x. Remember the admin username and password.

If you want to have full text search capability on Heroku, you should definitely use texticle or acts_as_tsearch. It is possible to use acts_as_farret on Heroku, but since you can only write to /tmp directory and your index file will be deleted sooner or later, you should not use it.

I first used texticle, and later switched over to acts_as_tsearch because I wasn’t happy with performance. Acts_as_tsearch is working really fine for me, and since your database on Heroku is already Postgres, there should be minimal configuration required. I even switched my local database from MySQL to Postgres to make both development and production environments consistent.

I have been using MySQL for probably as long as I could remember. For Bloglation, search capability is an important feature since it’s hard to browse each post one by one. I will probably implement tagging functionality, but even so, it’s important to be able to search the contents with a keyword(s). While Ultrasphinx works well, Heroku only supports WebSolr… I was using acts_as_ferret using /tmp for index files, but the problem using the /tmp directory is that ferret index files most likely to disappear at some point.

Then, I found out that Postgres supports full-text search and since Heroku uses Postgres, I could use other plug-ins like acts_as_tsearch or texticle for free. Free is important to me, since it’s not making any money.

Last Thursday, I released private alpha version of Bloglation, which lets a user translate any web page, save and share. It’s supposed to be private, but I need to get some good feedback from real users. If you are bi-lingual (or not) and interested in translating cool ideas, concepts and/or knowledge, please go ahead. And don’t forget to send me any comments/feedback you have.

I also wanted to maintain a separate blog just for bloglation. You can find it here.

This shouldn’t have been this difficult, but it has because while there are many cool tutorials are out there, they are mostly outdated, and for some reason, the instruction on Heroku was not accessible.

While I picked acts_as_ferret because Heroku supports it, many seemed to prefer Thinking Sphinx. So, if you are not constrained (like me with Heroku), you should try that out too.

1. Install acts_as_ferret

Full instruction is outlined on github, so you should check it out. You can also find the installation instruction and complete list of methods here, too.

While the instruction asks you to put version name, since Heroku only has version 0.4.3 installed, specifying a version will break it.