Notes posted by wiseleyb
RSS feedRedirect to subdomain
If you’re looking to redirect to a subdomain you can do things like this:
redirect_to users_url(1, params: {a: :b}, subdomain: 'bob')
Example from Code School
module Tweets
class ShowPresenter extend ActiveSupport::Memoizable def initialize(tweet) @tweet = tweet end def username @tweet.user.username end def status @tweet.status end def favorites_count @tweet.favorites.count end memoize :username, :status, :favorites_count end end
Example to auto download
Controller
op = Operation.find(params[:id]) fname = "operation_#{op.id}_#{DateTime.now.to_i}.csv" send_data op.export(params[:url_type]), :type => 'text/csv; charset=iso-8859-1; header=present', :disposition => "attachment; filename=#{fname}.csv"
export_csv
def export(url_type) csv_data = CSV.generate do |csv| csv << self.header_columns # simple array ["id","name"] url_items = @operation.url_items.where(:url_type => url_type) url_items.each do |url_item| csv << self.process_row(url_item) # simple array [1,"bob"] end end return csv_data end
unscoped.all / unscoped.count
At least in console, doing unscoped.all or unscoped.count initially returns expected results but, after you’ve added new records outside of the default_scope those two calls seem to use some cached values.
Therefore it should always be used with the block (as they sort of imply in the doc). unscoped { all } and unscoped {count }
Working with match captures
Let’s say you wanted to filter out passwords from:
s = "password=bob&password=jim&password=jane"
You’d do this:
r = /password\=([^\&]+)/ s.gsub!(r) { |m| m.gsub!($1, "[FILTERED]") }
Which would return
password=[FILTERED]&password=[FILTERED]&password=[FILTERED]
:method => :delete, etc.
If you’re upgrading to Rails 3 you’ll need to make sure you include rails.js (which is in public/javascripts when you rails new someproject) You’ll need to include it after prototype. And you’ll need to have a 1.7 version of prototype.
When you do a
link_to "Delete", @some_obj, :method => "delete", :confirm => "Are you sure?"
Rails 3 will generate
<a href="some_obj/id" data-confirm="Are you sure?" data-method="delete">Delete</a>
rails.js will creates observers that convert that into a form.
Be aware that this probably won’t work as a link from inside a form (since forms in forms isn’t valid).
Undocumented callbacks
Not sure why this isn’t documented… there are callbacks for before/after_add and before/after_remove. Example
has_many :things, :after_add => :set_things, :after_remove => :remove_things def set_things(thing) ... end def remove_things(thing) ... end
some gotchas
Works
named_scope :public, :conditions => "public = true"
Works
PUBLIC_CONDITIONS = "public = true" named_scope :public, :conditions => SomeModel::PUBLIC_CONDITIONS
Works
named_scope :public, lamba { {:conditions => SomeModel.public_conditions} } def self.public_conditions "public = true" end
Doesn’t work
named_scope :public, :conditions => SomeModel.public_conditions def self.public_conditions "public = true" end
update_all (and delete_all) don't play nicely with default_scope
If you have
class Topic < ActiveRecord::Base default_scope :conditions => "forums.preferences > 1", :include => [:forum] end
and you do a
Topic.update_all(...)
it’ll fail with
Mysql::Error: Unknown column 'forums.preferences' in 'where clause'
The work around for this is:
Topic.send(:with_exclusive_scope) { Topic.update_all(...) }
You can monkey patch this using this code (and requiring it in environment.rb or else where)
module ActiveRecordMixins class ActiveRecord::Base def self.update_all!(*args) self.send(:with_exclusive_scope) { self.update_all(*args) } end def self.delete_all!(*args) self.send(:with_exclusive_scope) { self.delete_all(*args) } end end end end
Then just you update_all! or delete_all! when it has a default scope.
Passing in parameters
If you want to pass in parameters you can do it like this:
User.get(:find_by_name, headers = {:name => "bob"}) => /users/find_by_name.xml?name=bob
For nested routes…
routes.rb
resources :companies do resources :users do member do get :find_by_name end end end
In your api code…
class User < ActiveResource::Base self.site = "/companies/:company_id" def self.find_by_name(name, company_id) User.get(:find_by_name, headers = {:name => name, :company_id => company_id} end end
Then doing…
User.find_by_name("bob", 1)
Would call
companies/1/users/find_by_name.xml?name="bob"
This works in Rails 3.1 - not sure about older versions (specifically I think the routes were done differently in < 3
Throw error after rollback
If you want to throw the exception after rolling back you can do something like this:
Company.transaction do user.save company.save x = 1/0 rescue exp = $! begin raise ActiveRecord::Rollback rescue end raise exp end
Rollback
To rollback the transaction…
transaction do unless user.save && company.save raise raise ActiveRecord::Rollback end end
Or - catch anonymous exceptions, roll back and re-throw error
transaction do user.save company.save x = 1/0 rescue exp = $! begin raise ActiveRecord::Rollback rescue end raise exp end
Add requires!
Useful for methods that take options = {}
class Hash def requires!(*params) params.each do |param| raise ArgumentError.new("Missing required parameter: #{param}") unless self.has_key?(param) end end end
keys to/from symbols
There’s probably a more effecient way to do this…
class Hash def keys_to_strings res = {} self.keys.each do |k| if self[k].is_a?(Hash) res[k.to_s] = self[k].keys_to_strings else res[k.to_s] = self[k] end end return res end def keys_to_symbols res = {} self.keys.each do |k| if self[k].is_a?(Hash) res[k.to_sym] = self[k].keys_to_symbols else res[k.to_sym] = self[k] end end return res end end
No Layout, other options
While it renders to the same rules as render, you need to specify params.
You’d think this would work:
render_to_string "users/profile", :layout => false
You need to do this instead
render_to_string(:layout => "users/profile", :layout => false)
Always gracefully degrade if JS isn't available
If you always want to degrade when JS isn’t available you can add something like to environment.rb
module ActionView module Helpers module PrototypeHelper def link_to_remote(name, options = {}, html_options = nil) html_options ||= {} html_options[:href] ||= options[:url] link_to_function(name, remote_function(options), html_options || options.delete(:html)) end end end end