Recent notes
RSS feedWhat's difference between create and new?
What’s difference between create and new?
Replacing with "\" and match
If you’re trying to place a “" in front of your matches, you’ll quickly see that it is a pain in the ass to add the quoting in the replacement string.
Here’s an example:
v = "Foo Bar!" # Target: Foo\ Bar\! # Resulting strings will not be quoted to decrease # the amount of backslashes. Compare \\! to "\\\\!" v.gsub(/\W/, '\0') #=> Foo Bar! # \\ escapes to a literal \, which next to the 0 becomes \0 v.gsub(/\W/, '\\0') #=> Foo Bar! # \\\0, means "\ \0", or "escaped \0" v.gsub(/\W/, '\\\0') #=> Foo\0Bar\0 # Same mechanism as before. \\ → \ v.gsub(/\W/, '\\\\0') #=> Foo\0Bar\0 # Finally! We have now an escaped \ before \0 and # we get the results we want. v.gsub(/\W/, '\\\\\0') #=> Foo\ Bar\! # It's very tempting to just write it like this now, right? v.gsub(/\W/) { |m| "\\#{m}" } #=> Foo\ Bar\! # It might not be shorter, but anyone can understand it.
Surely, there must be an easier way to do this. I haven’t found it, though. Hopefully, this makes it easier for you to understand why it behaves the way it does. :-)
Testing Regular Expressions?
Writing regular expressions is never easy. You may use http://rubular.com to test and optimize your regular expressions.
Capturing blocks after >2.2
After 2.2, you can omit the do …end block and simply use the &block variable directly:
concat(content_tag(:div, :class => "wrapped_content") do capture(&block) end, block.binding)
becomes simply:
concat(content_tag(:div, capture(&block), :class => "wrapped_content"))
IE GOTCHA - multiple javascript_include_tags with cache => true
If you have multiple lines of javascript_include_tag ‘jsfile’, :cache => true, IE does not load them all (though it seems Firefox and Safari do). And the error won’t show up until you’re in production (since that’s only when caching kicks in.)
You should include them all on one line:
javascript_include_tag 'file1.js', 'file2.js', 'file3.js', :cache => 'myfiles'
Clearing out previous values from content_for
By default, content_for :thing appends whatever you put in your block to the previous value of :thing. In some cases, you’d like to clear out :thing rather than append to it.
I just posted a way to do this on my blog: http://stevechanin.blogspot.com/2009/11/clearing-out-content-in-contentfor.html
I add a new method set_content_for that works just like content_for, but clears out :thing first. It doesn’t touch how content_for works, so it shouldn’t cause any problems anywhere else in your app.
You can specify the format as well
You can also specify the format (in case you need to redirect a request coming in one format to another format):
redirect_to :action => 'show', :format => 'html'
How to check if a Yield has content?
How do I do this without actually calling the yield?
- if yield :footer = yield :footer - else = render "layouts/footer_big"
(Note: HAML Syntax) Thanks.
How to use with HAML
Are you using HAML and try to do the block-thing (do…)? Please note that the whole block has to be in a single line. More: http://groups.google.com/group/haml/browse_thread/thread/52e62ef501c504a3
Streaming Does Not Work with Mongrel
If you are trying to stream output via render :text => Proc and Mongrel, be sure to note that this does NOT work. Mongrel returns a StringIO, which by nature buffers everything.
Unsure of how to actually stream output with Rails in a consistent fashion.
assert_response(:success) checks if the status code is in the range 200-299
success? in ActionController::TestResponseBehavior is defined as:
def success? (200..299).include?(response_code) end
Be careful with float ranges
Pay close attention to the fact that the object passed to :in must be enumerable.
If you want to validate a ranking, the following won’t work:
validates_inclusion_of :rating, :in => (0.0..10.0)
Instead, you’ll want to use validates_numericality_of like this:
validates_numericality_of :rating, :greater_than_or_equal_to => 0.0, :less_than_or_equal_to => 10.0
Example
code:
class Klass def set(string) var_name = "@#{string}" # the '@' is required self.instance_variable_set(var_name, 'bar') end def puts_foo puts @foo end end k = Klass.new k.puts_foo # nil k.set('foo') k.puts_foo # 'bar'
More Docs and Explanation
You probably want to look at the class level docs
http://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods
(cut and paste, apidocks can’t render the above for some reason)
The docs are in the base class
Look in ActionController::Base for the docs.
style for select
<%= select(“post”, “person_id”, Person.all.collect {|p| [ p.name, p.id ] }, {}, :style => “width:100px” %>
Careful with scopes
Just like find, find_in_batches introduces an implicit scope into the block. So for example
Person.find_in_batches(:conditions => {:birthday => Date.today}) do |birthday_childs| Person.all.each do |person| person.send_presents_to(birthday_childs) end end
does not work as expected, because the Person.all within the block will also find only persons with :conditions => {:birthday => Date.today}.
You can't use the :limit option either
Person.find_each(:limit => 10000)…
Will result in:
RuntimeError: You can’t specify a limit, it’s forced to be the batch_size
Rails documentation for nested attributes
ActiveRecord/NestedAttributes/ClassMethods
(don’t follow this link, the url interpreter isn’t rendering it correctly :(, but the correct link is at the top of this page)
Use hash form of updates argument
The examples are unfortunate, because passing a string as the updates argument is an invitation to SQL injection attacks. Don’t do this!
Billing.update_all("author='#{author}'")
Use the hash form of updates instead:
Billing.update_all(:author => author)
Then the SQL adapter will quote everything safely. Even if [you think] you’re sure there’s no quoting issue, it’s better to cultivate the habit of using the hash form just in case you missed something.
Same with conditions–use the hash or array form rather than a string if there are variables involved.
BTW, to do this and give options, of course you’ll need to put the braces back in:
Billing.update_all({:author => author}, ['title like ?', "#{prefix}%"])
Re: Taking care when writing regex
Oleg’s example from above contains an error and a pitfall:
validates_format_of :something => /^\w$/
The string “blahblahblah” doesn’t pass this validation. What Oleg ment is rather a continuous string of at least one alphanumeric character:
validates_format_of :something => /^\w+$/
However, that’s no good neither because it contains a well hidden trap in case you are validating content from a textarea.
Ruby (both 1.8 and 1.9) always matches ^ and $ against the beginning and ending of lines and not the entire string. Thus “First linenSecond line” will pass the above validation although it’s clearly not a continuous string.
You should use A (replacement for ^) and z (replacement for $) instead as their scope is the entire string:
validates_format_of :something => /\A\w+\z/
(A side note for those with a Perl background: Please note that the “s” modifier has a different meaning in Ruby and won’t do the trick here.)
Calling migrations within migrations observation
Following the advice from RISCfuture I could not call a migration from within another migration. I got the following errror message:
NameError Exception: uninitialized constant FixDrunkMistake::CreateExGirlfriendTexts.down
Only after I did a
require 'create_ex_girl_friend_texts' # the migration file
before the migration call did everything work as expected.
lower case am/pm
With DateTime#strftime you can also use %P to get a lowercase am/pm. Not so with Time#strftime though!
Where are the cached files?
If you configure your app to use the file_store like so:
config.cache_store = :file_store, '/tmp'
and expect you cached page pages to end up in /tmp, think again…
Rails – rather obscurely imho – will store page cached pages in the public/ folder of your app, making it easy for your webserver to find them.
The ‘page_cache_directory’ used in the ‘page_cache_path’ method above is a class var that defaults to the public/ dir.
overwrite
Replacing old value with new one
>> Module.const_set('MY_CONSTANT', 'value') => "value" >> Module::MY_CONSTANT => "value" >> Module.const_set('MY_CONSTANT', 'new value') (irb):3: warning: already initialized constant MY_CONSTANT => "new value" >> Module::MY_CONSTANT => "new value"
or
>> Kernel.const_set('MY_CONSTANT', 'value') => "value" >> MY_CONSTANT => "value" >> Kernel.const_set('MY_CONSTANT', 'new value') (irb):3: warning: already initialized constant MY_CONSTANT => "new value" >> MY_CONSTANT => "new value"
define_method with parameters
Just to be clear, you can do this:
define_method(:my_method) do |foo, bar| # or even |*args| # do something end
This means same as:
def my_method(foo, bar) # do something end
If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:
define_method(:my_method) do |foo, bar| bar ||= {} # do something end
Named scope better than conditions
In modern versions of Rails, in most cases a named_scope is a better alternative to using :conditions on your has_many relations. Compare:
class User has_many :published_posts, :conditions => {:published => true} end user.published_posts
with:
class Post named_scope :published, :conditions => {:published => true} end class User has_many :posts end user.posts.published
It’s better because the Post’s logic (“am I published?”) should not be coupled within User class. This makes it easier to refactor: e.g. if you wanted to refactor the boolean :published field into a :status field with more available values, you would not have to modify User class. Having to modify User when you refactor some implementation detail of Post class is clearly a code smell.
This also applies to :order, :group, :having and similar options.
As of v2.3.4 you can use Symbols
This commit fixes using a Symbol with assert_template
http://github.com/rails/rails/commit/f383a4aa333cd8a99003eb1bdbb27b6fdea1056c
assert_template :new # works in 2.3.4