Wednesday, June 30, 2010

MySql inconsistency when using Group By and Order By


I have a Ruby on Rails application where my development environment MySQL version is...

Server version: 5.0.45 MySQL Community Server (GPL)

And the production server (at Engine Yard) is...

Server version: 5.0.51-log Gentoo Linux mysql-community-5.0.51

This SQL satement:

SELECT id,name FROM properties GROUP BY id ORDER BY name DESC LIMIT 10;

Is sorted in Development, but not in Production (in production the results are sorted by ID)

Wednesday, May 19, 2010

Loading a partial with a Javascript Helper in Ruby on Rails

Sometimes, you have content that you want reloaded whenever someone goes to a page - even if they hit the 'Back' button. I had a drop down that I was using for navigation on Placeforce, and I wanted it to update even if they hit back. The drop down was your standard select tag, with a simple onchange event that would navigate the user to another page.

When you hit back, the select was still where it was left. This is good for forms, but not good in this case.

Here's a simple rails example to help you out:

< %= update_page_tag { |page| page[:content_div].replace_html(render(:partial => 'partial_to_render' ) ) } % >

The "render(:partial => ...) is what you're using now. Just wrap that with the update_page_tag { |page| page[:content_div].replace_html(...) }

Simple, took just a few minutes. I wasn't familiar with 'update_page_tag', so thought I'd share.

Thursday, May 06, 2010

Placeforce was officially launched

It's been 6 months of development, and Placeforce.com is finally released. I just added a tour to explain how placeforce works, and added links to sign-up, use a credit card, and get a free trial.

It's been a very interesting 6 months.

Back in November 2009, when we started, we had plans to release by February (3 months). We were targeting the Property Management industry, and trying to create a tool that Property Managers could use to allow their managers, building owners, and vendors to communicate and manage tasks and recurring maintenance. It was an ambitious project, but as we started to get feedback in January and February, we realized the vendor (the Window Cleaner, Plumber, Inspector, Electrician, etc) had a very clear need that we could solve first. Even for Property Management companies, they usually had a service department to handle handy-man projects, cleaning, etc. It changed our focus a little bit, for now.

We realized the tools that were being used by this group were completely substandard, and tended to focus around just one part of the task - Outlook or Google Calendar for scheduling, Appointment-plus sometimes, Quickbooks for billing, lots of rigged-together MSExcel solutions etc. Nothing, usually, for collecting or storing leads. Lots of paper laying around the office. Just a hodge-podge of tools and the owners of these companies were desperate for a solution. This also allowed us to simplify our story and focus on features that provide clear value.

We decided to concentrate on two things -
  1. Getting new customers
  2. Servicing those customers
Placeforce centers around scheduling tasks for properties - this includes photos, maps, documents, geo-location, etc. Having a easy access to property information can greatly improve the efficiency of your business - take a look at an article my brother, Eric recently posted on our blog - Three Keys to Managing Better with Property Information. Placeforce has potential for a strong mobile component, as well (coming soon, hopefully). And, unlike other tools out there, we did not build a generic tool for any industry, we're specific to property-based service companies. This narrows our potential customer pool, but allows us to really focus on what our true customers need.

Saturday, March 20, 2010

ActiveRecord::SerializationTypeMismatch (search_fields was supposed to be a Hash, but was a String):

This error was happening on a field that stored a serialized Hash.

It appears the size of the field was too small. I had it at a string varchar(255) and after changing it to a limit of 1000, the error went away.

change_column :users, :search_fields, :string, :limit => 1000

I presume this is due to a few characters at the end getting cut off, so the data structure no longer matched a hash.

Monday, March 01, 2010

Rails Exception Logger Plugin

This is simple to set up, but not so easy to find on the web. Just writing it down so it's easier to find in one place.

First install the plugin. Do this from the app_root directory.

script/plugin install git://github.com/defunkt/exception_logger.git

Next, generate the migration and run it:

script/generate exception_migration
rake db:migrate

Add this to your ApplicationController

class ApplicationController
include ExceptionLoggable

Then, add to routes the following:

map.connect "logged_exceptions/:action/:id", :controller => "logged_exceptions"

Restart your system to pick up the plugin.

Pagination
To get pagination working with will_paginate, go into plugins/exception_logger/init.rb and modify it so it looks like this.

#$PAGINATION_TYPE = 'none'
require 'will_paginate'
$PAGINATION_TYPE = 'will_paginate'
WillPaginate.enable
#require 'paginating_find'
#$PAGINATION_TYPE = 'paginating_find'
LoggedExceptionsController.view_paths = [File.join(directory, 'views')]

And, in my case, I didn't have redcloth installed, so I modified plugins/exception_logger/views/logged_exceptions/_show.rhtml

I removed textilize and used 'simple_format'

By the way, there is part of the logged_exceptions README that encourages you to overwrite a few methods, including render_404(exception)

To do this, you would do something like the following. In your application_controller:

def render_404(exception)
log_exception(exception)
render :file => '/errors/400', :status => 400
end

This would be good if you wanted to reuse your layouts and show a dynamic page instead of using one of the static pages in the /public directory.

One last thing
If you want to restrict access to the logged_exception controller and you are using authlogic from binary logic, here is one way to do it:

In authorization_rules.rb, add the privilege to manage logged_exceptions

role :administrator do
has_permission_on :logged_exceptions, :to => :manage
end

Then, in the plugins/exception_logger/lib/logged_exceptions_controller.rb

I changed the file to look like this:

class LoggedExceptionsController .. ApplicationController

filter_access_to :query, require => :manage
filter_access_to :destroy_all, :require => :manage

And - the icing on the cake. I a free rss app for the iphone. Entered the url for the rss feed with the authlogic user_credentials parameter attached to the url

http://yourapp.com/logged_exceptions?format=rss&user_credentials=single_access_token

You can get the single_access_token from the user table - just use your admin user to access the rss feed. Very handy to have an rss feed of the latest exceptions right on your iphone. You can also modify the views to add more information to the rss item if you need to.

Friday, February 12, 2010

Thinking Sphinx installation, indexing, deploying on Engine Yard

This took a few days, but it's very simple to do and should take minutes. If you're using Engine Yard Cloud, it's not obvious, but it is trivial. The post assumes you have Thinking Sphinx and the Sphinx daemon running on your dev machine and aren't new to either. I used the Thinking Sphinx plugin, as Engine Yard recommends, but I see there is also a gem which my work.

I'm working from memory here, so please let me know if you find any details missing or unclear.

Here's the steps I took:

First you need to clone the engineyard github repository for their chef recipes. This is how engine yard knows you want to have the sphinx daemon running.

I cloned this to my app root, but it probably didn't matter. You don't check it in.

http://github.com/engineyard/ey-cloud-recipes

Once you have this, you edit line 10 in the cookbooks/thinking_sphinx/recipes/default.rb file.

10. run_for_app("app_name") do |app_name, data|

Just add your engine yard app_name here.

Then follow the Installation instructions on the bottom of that page.

Indexing
You'll want to index regularly. For this, I set up a cron job.

cd /data/app_name/current && rake ts:index RAILS_ENV=production

Note: this didn't work for me at first. Not sure why. It could have been a spelling mistake or maybe it had something to do with how I was setting up the deployment. I'll describe deployment next.

Deployment
When you deploy on Engine Yard, you need to stop, index, and start thinking sphinx. To do this, you need to make a "deploy" directory under your rails app_root. For me, I have one file in there "after_restart.rb" and the contents of this file is just this:

sudo "cd #{current_path} && rake ts:stop RAILS_ENV=production"
sudo "cd #{current_path} && rake ts:index RAILS_ENV=production"
sudo "cd #{current_path} && rake ts:start RAILS_ENV=production"

Note: this also didn't work for me right away. I was getting an error that said it could not cd because the directory didn't exist, but I stopped seeing that error. Not sure why this happened.

More information
You may have done some searching to figure around this issue already. When I searched, I found there was a lot of extra or mis- information that made it tough to figure out what to do in production. There are many documents on Engine Yard about this, including the following:

http://www.engineyard.com/blog/2009/5-tips-for-sphinx-indexing/
https://cloud-support.engineyard.com/discussions/questions/265-thinking-sphinx

But these documents all seem to be out of date, at least for a Cloud deployment. Please read these to see if they apply to your needs, but they seem to contain a lot of information that was either old, or did not apply to the standard deployment.

Engine Yard support
When I wrote Engine Yard to ask for a clarification to the online docs, they said that I could submit a ticket to get an answer (this requires the $200+ per month service). It really seems like this should have been a quick answer for them, in the knowledge base somewhere, or worthy of a comment in their online docs. I didn't end up buying the support package, but may in the future.

Also, I posted a question on the community support forum, not the cloud support forum. I didn't realize these were different. The UI is identical and I'm not really sure how I got to the wrong site. Keep that in mind if you're asking for help in the forums.

Anyway, hope this helps someone save some time.

Friday, January 22, 2010

Rails Autocomplete without Ajax (Autocompleter.local)


This was fun - though not easy to find the answer right away.

I wanted to add an autocomplete to a form, but I wanted the suggestions to be local (I didn't want to make any ajax requests, I wanted to use a pre-defined javascript array).

This ended up to real easy.

The scenario here - I have a nested set of objects that an admin may want to give membership privileges to an existing user in their system. The number of existing users, is low (< 100).

For this to work, I had a @member_emails variable accessible to the view. This held all the emails from members that were already members somewhere else in the system.

With this, admins are able to access existing users or add new users quickly.


<%= f.label :user_email, "User's email" %>
<%= f.text_field :user_email, :autocomplete => "off" %>
< div class="auto_complete" id="user_email_auto_complete" >< /div >

<%= javascript_tag("new Autocompleter.Local('membership_user_email', 'user_email_auto_complete', [#{ @member_emails.map{|e| "'" + e + "'" }.join(',') }] , {fullSearch: true, frequency: 0, minChars:1});") %>