Great stuff I tweeted on 2009-02-25
- Government buildings in hamilton. So depressing, but this greeter is strangely cheery. #
Just spent an hour or so trying to figure out why my Sinatra app running DataMapper couldn’t write to my sqlite database, and kept returning the vague error “Unable to Open Database”. Turns out the problem is as simple as making sure that the user running the script not only has write permissions on the database file, but also on the directory that the datbase file is in. If you find yourself getting this error and you can’t figure out why, that’s probably the problem!
Paperclip is hands-down the best file attachment plugin for Rails. File_column was alright a while back, and attachment_fu was a frustrating mess. One thing I don’t like about Paperclip though is that by default it fills your public folder with uploads. (NOTE: As of the latest version of Paperclip this is no longer true.) This is even worse if you have an attachment called “images” as they just get dropped into your images folder.
While it’s fairly easy to redefine where the attachments get saved on a per-model basis with the :url and :path options, I very much prefer to do something once and then never have to think about it again. (This preference is part of the reason that this is only my second post on a blog I’ve had since December.) Thankfully, overriding the defaults for your entire app is easy. Just make a file called paperclip_defaults.rb in your config/initializers directory and fill it with the following lovely code:
module Paperclip
class Attachment
def self.default_options
@default_options ||= {
:url => "/system/:class/:attachment/:id/:style/:basename.:extension",
:path => ":rails_root/public/system/:class/:attachment/:id/:style/:basename.:extension",
:styles => {},
:default_url => "/:attachment/:style/missing.png",
:default_style =>
riginal,
:validations => [],
:storage => :filesystem
}
end
end
end
Just change the options in that block to suit your fancy, and the changes will take place across your entire application.
Using a conditions hash isn’t always my favourite way to write finds in Rails, but in certain cases it’s an indispensible tool for building queries. It’s especially handy when you’re building an advanced search where conditions may or may not be present.
Recently I ran into an issue where I needed to run conditions on an associated table in just such a search and I managed to find what seems to be an undocumented (or under-documented at least) feature of ActiveRecord. For the sake of using the same example as every other Rails tutorial out there, let’s assume that I’m running a search on Authors, and that an Author has_many books. All we have to do is make a hash within the conditions hash with the name of the associated table. Searching both tables is easy as:
Author.find(:conditions => {:first_name => params[:first_name], :last_name => params[:last_name], :books => { :title => params[:book_name] } }, :include => :books)
If we were writing this as an advanced search and wanted the parameters to be optional, we would break it out like this:
conditions = {}
conditions[:first_name] = params[:first_name] unless params[:first_name].blank?
conditions[:last_name] = params[:last_name] unless params[:last_name].blank?
conditions[:books] = {:title => params[:book_name]} unless params[:book_name].blank?
@authors = Author.find(:conditions => conditions, :include => :books)
Simple!