Archive for the ‘ Rails ’ Category

Model Specific Formatted Search Results Using Thinking Sphinx

Monday, February 8th, 2010

Having recently implemented Thinking Sphinx on one of my web sites, I thought it would be cool to be able to search every indexed model. With Thinking Sphinx, it’s easy to have a bunch of different classes returned in the results. The tougher part is displaying them in a way that is organized (although admittedly not very DRY).
(more…)

Sitemaps On Rails

Thursday, December 17th, 2009

SEO being an interest of mine, I couldn’t quite wrap my head around releasing a webapp without a sitemap. The problem is that there aren’t any really great sitemap plugins for Rails. Now I will grant that creating a sitemap in Rails is a challenging proposition and one that I would not like to undertake on my own unless absolutely necessary. But I was hoping that there would be a rails sitemap “killer app” like there is with almost everything else in Rails.

So I dove in and tried a few options until I found one that worked. First I wrote some code to generate an XML file and then created a sitemap_index.xml.gz file by hand. This was very kludgy and definitely not a permanent solution. I had also read suggestions about doing it in a sitemap_controller.rb file, but that seemed just as kludgy as using a view to generate the XML. It was then time to explore the plugin world.
(more…)

Custom Google Maps Marker With YM4R_GM

Monday, December 14th, 2009

In one my Rails applications, I allow the user to search for surrounding businesses from their current location. I always showed them a You Are Here marker. The issue I had with this was that the marker was always the icon as the search results. Differentiating these markers is actually extremely easy with ym4r_gm plugin.

First thing is to find a custom icon that you want to use. You can just Google for custom Google maps icons. I chose to use their default icon, just in a different blue. (You can download it here so you are working with what I am working with for this example). The next thing I did was to use the Google custom markers web site to find the proper config options for the icon.
(more…)

Country-State Select Using Carmen and jQuery

Monday, December 7th, 2009

I’ve been wanting to find a way to use drop down menus for countries and their states when they exist. But keeping a list on my own would have been a huge pain in the ass. So rather reinvent the wheel, I found the Carmen plugin for Rails. All I have to do is keep the plugin updated and my list of countries and their states will be kept updated as well.

How do I do all this with unobtrusive Javascript and Rails you ask? Good question. Let me show you. Don’t forget to install the plugin (or use the gem).

Let’s start out by adding the drop down menu to our view. In my case I have it in a partial for the address part of a form. You’ll have to modify this slightly to pick up the values of the form if the partial handles edits as well. This one is just for a new method as it uses a default country of US and its states. Note the div ID here of addressStates; we will be using this later in the javascript.
(more…)

Adding AJAX Bookmarks to Your Rails Application (Part 2 of 2)

Wednesday, November 25th, 2009

In part 1 of this series, we discussed the base models, controller, database migrations necessary to get this project off the ground. Now we are going to continue with this functionality

Let’s take a look at what needs to go into the models to support this. If you have a model that uses a slug generated via to_param, then your code will look like the top model, If you are using the normal numeric id convention, then it will look like the bottom model. The reason for the specifically named methods get_title and get_description will become apparent when you start displaying bookmarks. The thought process is that you can use a consistent set of calls for displaying the bookmark information and put the code to grab that information in the model where it belongs rather than loading up the helper methods. What should also be noted is that the title and description fields are not always consistent across models. Therefore the method naming conventions returns the proper column with consistent method names.
(more…)

Adding AJAX Bookmarks to Your Rails Application (Part 1 of 2)

Monday, November 23rd, 2009

It you want to add the ability to bookmark pages in your Rails application, its actually a fairly straightforward thing to do. You can even do them in AJAX. There may be better ways to do this, but this way is somewhat abstract and it works for me, so hopefully it can work for you too. It is abstract in the sense that it will work for models with different URL styles and different column names.

The way this works is that you add a bookmark icon (which is initially disabled) to a show <model_name> page. When the user clicks on the bookmark icon, an AJAX query will be made in the background and update the users bookmark lists. I am approaching this from an abstract methodology. Meaning that I have “forced” these methods to work with models executed in various fashions (as I give examples of below). The AJAX call is going to be simply work as a toggle. It will actually call a toggle method in the bookmarks controller and change the current value and replace the image. The user can then view the pages they have bookmarked in their profile.

I have decided to break this into a multi-part blog entry because it ends up being quite long. Not necessarily in how long it takes, just the amount of space it takes to show all the code. I have done my best to only show relevant code and maintain brevity. Note: I will not cover how to allow for unobtrusive AJAX calls. That is beyond the scope of this set of posts.
(more…)

One Time Modal Windows With Rails and Fancybox

Tuesday, November 3rd, 2009

Let’s say that you have a situation that you want to have a modal window show up only once for each user. It’s actually not that difficult although lots of Googling around got me nowhere. I am choosing to use FancyBox for my modal window, but feel free to use your modal framework of choice. So let’s get down to business.

First thing you’ll need to do is download FancyBox and copy the stylesheets, images, and Javascript files to their proper/desired location in your Rails app. Style the window according to your likings.

Whether it is right or wrong, I did this entirely in the view, without even pulling the Javascript out into the application.js (or even another Javascript file for that matter). My reason was that I only want the modal window showing up on this page. If you want your modal window to show up somewhere else (or on every page), then put the code in your layout. But remember that this call will be executed every time the page loads. I put mine in a profile page which doesn’t get accessed that often so the conditional is not checked quite as frequently.

My application uses Facebook Connect and grabs the users Facebook Proxy email address (FB app developers will know what this is). So I check if that’s the email I have for the user. If yes, then I pop up a modal window on page load only once to get their regular email address and possibly a password so they can login to their account without Facebook Connect if they want. When the modal window is shown, a variable is set in the cookie (note that this cookie is shared with authlogic for sessions) to ensure that the modal window isn’t shown again.
(more…)

Migrations Without belongs_to Or references

Wednesday, October 14th, 2009

Normally when do a database migration in Rails, when adding ownership from a model to another model, you use the concept of belongs_to or references:

1
2
3
4
  create_table :comments do |t|
    t.belongs_to :user
    t.references :post
  end

Interestingly enough, these methods are only available during the initial table creation. If you want to add a reference to a model that is created later, you have to do it the old fashioned way, by just adding a column:

1
   add_column :comments, :group_id, :integer

Doing it this way is clean, easy, and definitely meets the KISS principle. But I do find it interesting that one can’t add an association later in the game. Sometimes the Rails way is just KISS and adding the column by hand.

Fixing zlib Errors On Capistrano Deploy

Sunday, October 4th, 2009

Ever since I started doing Capistrano deploys from my Mac, I have been seeing the following error:

zlib(finalizer): the stream was freed prematurely.

The error seems harmless, but I figure that errors are there for a reason and the Sysadmin in me decided to try to get rid of it. A quick Google for an answer said something about adding the following line of code to you Capfile (or in my case, I separated it out to my config/deploy.rb:

1
ssh_options[:compression] = "none"

I couldn’t actually find the reason for this. But I guess finding the solution is good enough for now.

Shortcut Notation in Rails Callbacks

Sunday, August 16th, 2009

As I have spent the last few weeks/months learning Ruby and Rails, I have grown to love it more and more. The ease of use and the high learning curve make is fantastic for people like me who aren’t developers by nature.

I have recently come across a scenario in Rails that there is not yet a shortcut for. If you have a method that you want to execute in a few different callbacks, there is no shortcut for it. ie, I have the following:

1
2
3
  after_create   :methodFoo
  after_save     :methodFoo
  after_destroy  :methodFoo

I would like to be able to write this as:

1
 after_create, after_save, after_destroy => :methodFoo

This would obviously only work if the callbacks were then treated as arrays of functions and each time a callback was found in the model, the method was pushed onto the array.

Adding An Average Column To A Model

Friday, August 14th, 2009

Using Ruby on Rails is all about what people find to be common uses. These items then become part of the core system. An example of this is counter_cache. For more information on this, I suggest checking out the Railscast on it here.

A little more of an edge case is if you want a column that rather than counting totals, its calculates an average. To me this is just common enough to require a HOWTO and not common enough to be in the core rails system. Hence here is my HOWTO.

Context: Let’s use an example similar to Yelp where there is a business and each business gets reviewed. The review count is handled by the counter_cache so that column already exists in our database.

1
| reviews_count | INT(11)      | YES  |     | 0       |                |

The trick here is that every review also has a rating of the business being reviewed. So we are going to use this rating column from the reviews table to calculate the average rating of a business.

First thing we need to do is create the migration:

1
2
3
beacon:test elubow$ script/generate migration add_average_rating_to_business
      exists  db/migrate
      create  db/migrate/20090811135219_add_average_rating_to_business.rb

Edit the migration file to look like this (Note: I know the precision here is 2 when the idea is to not go greater than 5, but MySQL requires precision to be >= scale):

1
2
3
4
5
6
7
8
9
class AddAverageRatingToBusiness < ActiveRecord::Migration
  def self.up
    add_column :businesses, :average_rating, :decimal,  :precision => 4, :scale => 2
  end

  def self.down
    remove_column :businesses, :average_rating
  end
end
1
2
3
4
5
6
beacon:site elubow$ rake db:migrate
(in /Users/elubow/Sites/site)
==  AddAverageRatingToBusiness: migrating =====================================
-- add_column(:businesses, :average_rating, :decimal, {:scale=>4, :precision=>2})
   -> 0.7018s
==  AddAverageRatingToBusiness: migrated (0.7021s) ============================

Now we are going to use the after_save callback hook. We are using after_save because we want the current change to be entered into the database before we make any calculations. In our reviews model, we are going to the following lines:

1
2
3
4
5
6
7
8
9
10
  after_create   :update_business_average_rating
  after_save     :update_business_average_rating
  after_destroy  :update_business_average_rating

  def update_business_average_rating
    average_rating = Review.average(:rating, :conditions => [ 'business_id = ?', business_id ] )
    business = Business.find(:first, business_id)
    business.average_rating = average_rating
    business.save
  end

Let’s walk through this line by line (Note: The business ID and actual ratings will be different based on your data). First, we grab the average rating from every review of that business. What I would like to note is that by default since it is a callback, the review just added is automagically passed into the method. That is how we are able to access the business_id both to find the average of all the reviews of that business, but to also find the business record to update the average_rating attribute.

The method above causes the following SQL to execute:

1
SELECT avg(`reviews`.rating) AS avg_rating FROM `reviews` WHERE (business_id = 1)

The next line finds the record of the business and updates it with the newly calculated average rating. The resulting executed SQL will be this:

1
UPDATE `businesses` SET `average_rating` = 3.0, `updated_at` = '2009-08-13 22:08:55' WHERE `id` = 1

Now that we’re done adding the column and calculating its value, don’t forget to add it to your view. A simple display should do just fine.

1
< %=h @business.average_rating %>

Checking Roles in Views Using RoleRequirement

Thursday, August 6th, 2009

One of the rails projects I am working on is using the RoleRequirement plugin. This is a great plugin for seamless integration of roles into the controller level, but there wasn’t really much documentation on integrating this into the views themselves. So I figured I would put this little gem out there which has done wonders for the DRYness and cleanliness of my code.

For instance, the code below checks whether or not the current user has the admin role. If they do, it prints the admin menu (in my case I use a partial for this).

1
2
3
4
5
6
< % if current_user.has_role?('admin') %>
<!-- Begin Admin Panel -->
<h2>admin</h2>
< %= render :partial => '/layouts/admin' %>
<!-- End Admin Panel -->
< % end %>

The great thing is that (although it might be a little unclean), you can chain some conditionals here to show the appropriate menu items based on a users role(s). This is powerful because a user< ->role relationship is a HABTM (Has And Belongs To Many) relationship.

Testing Sessions with Digest::SHA256 Passwords In Rails

Friday, July 17th, 2009

I am fairly new to Rails, but from what I have learned thus far, its fantastic. I plan on posting more obscure Rails items as I come across them.

I am writing an application that is similar in functionality to Yelp (in some ways). I have had some help along the way from a seasoned Rails vet. One of the things he helped me with was setting up the sessions_controller. He did this in such a way that I wasn’t initially sure how to write the functional tests for it. The sessions_controller contained code like this (it’s a bit more in depth than this, but this will give you the idea):

1
2
3
4
5
6
7
8
def create
    @current_user = User.find_by_username( params[:username] )
    if @current_user.nil? or Digest::SHA256.hexdigest( params[:password] + @current_user.password ) != @current_user.password_salt
      redirect_to( login_path )
    else
      redirect_to( user_path )
  end
end

So when it came time to write the functional tests for this (using fixtures), I couldn’t get away with just a user.yml like this:

1
2
3
4
5
6
7
8
test_user:
    username: test_user
    password: secretuser
    firstname: General
    lastname: User
    email: test_user@user.com
    role: normal
    nickname: Mr. Testy

The reason for this is because the user table contains an extra column pertaining to the password called password_salt (which you’ll notice referenced above). Therefore my user fixture needed to look something more like this:

1
2
3
4
5
6
7
8
9
test_user:
    username: test_user
    password: A0Mrhnu4  # secretsalt
    password_salt: 868532ea243f03c2ce5f6f99dcf9e27342c39ce51819fa0605302ab4b5c3841e
    firstname: Test
    lastname: User
    email: test_user@example.com
    role: normal
    nickname: Mr. Testy

The other fixture still has it usefulness in testing (like testing logins that won’t work), so don’t get rid of it so quickly.

How do I generate that salt and the hashed password? I’m glad you asked. I’m sure there is a better way to do it than I did, but I just went into the application, created a user and then went into the console, grabbed the user information and copied it into the fixture. Then I used the following code in my sessions_controller_test.rb for the functional test:

1
2
3
4
5
  def test_should_logout_and_clear_session
    post :destroy, :username => 'test_salt', :password => 'secretsalt',
      :return_to => '/'
    assert_redirected_to '/'
  end