<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>{ Rails + Love } - Home</title>
  <id>tag:blog.marcslove.com,2007:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  <link href="http://blog.marcslove.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://blog.marcslove.com/" rel="alternate" type="text/html"/>
  <updated>2007-07-18T16:27:45Z</updated>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-06-30:16</id>
    <published>2007-06-30T02:01:00Z</published>
    <updated>2007-07-18T16:27:45Z</updated>
    <link href="http://blog.marcslove.com/2007/6/30/iphone-optimization-stylesheet_link_tag-caching" rel="alternate" type="text/html"/>
    <title>iPhone Optimization: stylesheet_link_tag caching</title>
<content type="html">
            &lt;p&gt;This change to the Rails core is a couple months old, but especially relevant when developing for the iPhone.  One of the ways to optimize the performance of apps delivered to iPhones is to reduce the number of requests required for each action.  If you like to split up your css files in logical order like I do, then you might find the stylesheet_link_tag caching useful.&lt;/p&gt;


Before:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;stylesheet_link_tag :all # returns =&amp;gt;
  # &amp;lt;link href=&quot;/stylesheets/style1.css&quot;  media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;
  # &amp;lt;link href=&quot;/stylesheets/styleB.css&quot;  media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;
  # &amp;lt;link href=&quot;/stylesheets/styleX2.css&quot; media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;

stylesheet_link_tag &quot;shop&quot;, &quot;cart&quot;, &quot;checkout&quot; # returns =&amp;gt;
#  &amp;lt;link href=&quot;/stylesheets/shop.css&quot;  media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;
#  &amp;lt;link href=&quot;/stylesheets/cart.css&quot;  media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;
#  &amp;lt;link href=&quot;/stylesheets/checkout.css&quot; media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

After:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;stylesheet_link_tag :all, :cache =&amp;gt; true # returns =&amp;gt;
  # &amp;lt;link href=&quot;/stylesheets/all.css&quot;  media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;

stylesheet_link_tag &quot;shop&quot;, &quot;cart&quot;, &quot;checkout&quot;, :cache =&amp;gt; &quot;payment&quot; # returns =&amp;gt;
#  &amp;lt;link href=&quot;/stylesheets/payment.css&quot;  media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You need to have &lt;code&gt;ActionController::Base.perform_caching = true&lt;/code&gt; for this to work.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-06-29:15</id>
    <published>2007-06-29T08:27:00Z</published>
    <updated>2007-07-18T16:27:34Z</updated>
    <link href="http://blog.marcslove.com/2007/6/29/respond_to-iphone-in-rails" rel="alternate" type="text/html"/>
    <title>respond_to :iPhone in Rails</title>
<content type="html">
            &lt;p&gt;As promised in &lt;a href=&quot;http://blog.marcslove.com/2007/6/28/iphone-interface&quot;&gt;my prior article&lt;/a&gt;, here is my current solution to quickly and easily tack on an iPhone specific user interface to Rails applications.  Our goal is to be able to deliver customized html, js and css for the iPhone.  To do so, I&#8217;ve decided to hijack our best friend &lt;code&gt;respond_to&lt;/code&gt;.  &lt;code&gt;respond_to&lt;/code&gt; delivers different content to browsers based on their &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; request and even though its only designed to discriminate based on mime-type, its pretty easy to modify it to also discriminate based on user-agent.  The other distinct advantage of using &lt;code&gt;respond_to&lt;/code&gt; is that not only can we create different html, javascript and css views, but we can also pass blocks.&lt;/p&gt;


	&lt;p&gt;If you want to follow along in the core, open up &lt;code&gt;actionpack/lib/action_controller/mime_responds.rb&lt;/code&gt; and scroll down to the &lt;code&gt;Responder&lt;/code&gt; Class.&lt;/p&gt;


	&lt;p&gt;The &lt;code&gt;initialize&lt;/code&gt; method checks the &lt;span class=&quot;caps&quot;&gt;CGI&lt;/span&gt; request for the list of acceptable formats and puts them in an array in order of preference (&lt;code&gt;@mime_type_priority&lt;/code&gt;).  Later it iterates through this array and returns the first one that matches what&#8217;s listed in &lt;code&gt;respond_to&lt;/code&gt;.  Let&#8217;s modify it to automagically add iPhone specific &lt;span class=&quot;caps&quot;&gt;MIME&lt;/span&gt; types to the front of that preference array.&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;alias original_initialize initialize

def initialize(controller)
  original_initialize(controller)
  # If the user agent is Safari on iPhone, duplicate the acceptable
  # formats with iphone_ prepended versions
  if @request.user_agent.include?('iPhone')
    # We only need to duplicate html, js &#38; css mime-types
    mime_types_to_duplicate = @mime_type_priority.select do |m|
      [Mime::EXTENSION_LOOKUP['html'], Mime::EXTENSION_LOOKUP['js'], Mime::EXTENSION_LOOKUP['css']].include?(m)
    end
    # Retrieve iPhone mime-types
    mime_types_to_duplicate.map!{ |m| Mime::EXTENSION_LOOKUP[(&quot;iphone_&quot; + m.to_sym.to_s)] }
    # and place them first in the priority list.  If they exist, they'll
    # be delivered first.  If they don't, then iPhone requests will fallback
    # on the standard html/js/css responses.
    @mime_type_priority =  mime_types_to_duplicate + @mime_type_priority
  end
end
&lt;/code&gt;&lt;/pre&gt;

When &lt;code&gt;respond_to&lt;/code&gt; is called, it creates a new &lt;code&gt;Responder&lt;/code&gt; object and calls it&#8217;s &lt;code&gt;respond&lt;/code&gt; method.  Eventually &lt;code&gt;method_missing&lt;/code&gt; is called on the &lt;code&gt;mime_type&lt;/code&gt; names which sends those names on to the &lt;code&gt;custom&lt;/code&gt; method.  &lt;code&gt;custom&lt;/code&gt; generates a response for that mime-type.  We have to grab these iPhone mime-types before they are processed by &lt;code&gt;custom&lt;/code&gt;, otherwise we&#8217;ll end up sending a response to the browser with an invalid content-type header for our fake iPhone mime-types.  So let&#8217;s change &lt;code&gt;method_missing&lt;/code&gt; to this:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;def method_missing(symbol, &#38;block)
  mime_constant = symbol.to_s.upcase

  # Intercept iphone_ prepended acceptable mime-types and send them to our
  # custom_iphone response constructor
  if mime_constant.include?('IPHONE_') &#38;&#38; Mime::SET.include?(Mime.const_get(mime_constant))
    custom_iphone(Mime.const_get(mime_constant), &#38;block)
  elsif Mime::SET.include?(Mime.const_get(mime_constant))
    custom(Mime.const_get(mime_constant), &#38;block)
  else
    super
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now we need to create our &lt;code&gt;custom_iphone&lt;/code&gt; method which creates the response just like &lt;code&gt;custom&lt;/code&gt; except it changes the content-type header to the valid content-type:&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;def custom_iphone(mime_type, &#38;block)
  mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
  # Remove the &quot;iphone_&quot; part of the name and retrieve the valid mime-type object
  actual_mime_type = Mime::Type.lookup_by_extension(mime_type.to_sym.to_s[7..-1])

  @order &amp;lt;&amp;lt; mime_type

  if block_given?
    @responses[mime_type] = Proc.new do
      @response.template.template_format = mime_type.to_sym
      # Deliver the valid mime-type instead of our fake iphone one
      @response.content_type = actual_mime_type.to_s
      block.call
    end
  else
    @responses[mime_type] = Proc.new do
      @response.template.template_format = mime_type.to_sym
      # Deliver the valid mime-type instead of our fake iphone one
      @response.content_type = actual_mime_type.to_s
      @controller.send :render, :action =&amp;gt; @controller.action_name
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

One last thing.  We need to register our fake iPhone &lt;span class=&quot;caps&quot;&gt;MIME&lt;/span&gt; types:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;Mime::Type.register &quot;iphone/html&quot;, :iphone_html
Mime::Type.register &quot;iphone/javascript&quot;, :iphone_js
Mime::Type.register &quot;iphone/css&quot;, :iphone_css
&lt;/code&gt;&lt;/pre&gt;

A little hacky?  Yea.  I&#8217;m not so happy with creating fake &lt;span class=&quot;caps&quot;&gt;MIME&lt;/span&gt; types and &lt;code&gt;respond_to&lt;/code&gt; wasn&#8217;t meant to identify user-agents, but it&#8217;ll work until I can figure out a cleaner implementation.  There&#8217;s no denying the benefits of harnessing the power of &lt;code&gt;respond_to&lt;/code&gt;.  It makes developing a separate UI for iPhones super simple.  Now you can do things like:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;respond_to do |format|
  format.html
  format.iphone_html
  format.js
  format.iphone_js
end
&lt;/code&gt;&lt;/pre&gt;

Want to redirect iPhone users away from a particular method?:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;respond_to do |format|
  format.html
  format.iphone_html{ redirect_to( :action =&amp;gt; &quot;index&quot;) }
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;No need to modify any of your other application code or existing views.  Just add the &lt;code&gt;.iphone_*&lt;/code&gt; templates (i.e. index.iphone_html.erb, index.iphone_js.erb) and modify your &lt;code&gt;respond_to&lt;/code&gt; blocks.  &lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;GOTCHA ALERT&lt;/span&gt;:&lt;/strong&gt; regular and iPhone-specific html templates will share the same layout if one is designated at the controller level.  To hide parts of your layout files from iPhone requests, just do:&lt;/p&gt;


&lt;code&gt;primary_layout.html.erb&lt;/code&gt;:
&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&amp;lt;% unless request.user_agent.include('iPhone') %&amp;gt;
Hidden from iPhones
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-06-28:14</id>
    <published>2007-06-28T06:18:00Z</published>
    <updated>2007-07-18T16:27:11Z</updated>
    <link href="http://blog.marcslove.com/2007/6/28/iphone-interface" rel="alternate" type="text/html"/>
    <title>Development for iPhone</title>
<content type="html">
            &lt;p&gt;Normally I wouldn&#8217;t advocate developing completely different views for one particular user-agent.  It violates the web standards mindset that has been burned into my brain over many years.  However, I can&#8217;t ignore the fact that the iPhone throws a wrench into some of that mindset.  The iPhone&#8217;s full web browser will be great for reading news sites &#38; blogs, but for web apps, we should take a couple things into consideration:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Every kilobyte matters!&lt;/strong&gt;  The &lt;span class=&quot;caps&quot;&gt;EDGE&lt;/span&gt; network will have users crawling the web, quite literally.  Download speeds will float somewhere between that of a 56kbps modem and an &lt;span class=&quot;caps&quot;&gt;ISDN&lt;/span&gt; line when users are away from WiFi.  Hiding elements with media-specific stylesheets does us no good because the data is still downloaded (including all those hefty javascript libraries).  Which brings me to my next point&#8230;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;iPhone will probably use &#8220;screen&#8221; css media, not &#8220;handheld&#8221;&lt;/strong&gt; (pretty clear from the public demonstrations and Apple&#8217;s huge emphasis on it having a &#8220;FULL web browser&#8221; and browsing the web the &#8220;way it was meant&#8221; to be browsed).  After all, what&#8217;s the point of having a phone with a full web browser complete with zoom-in, zoom-out capability if the browser loads stripped down versions of web pages by default?  Again, great for browsing, not for monitor-sized web apps.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Using web apps on the iPhone will be cumbersome enough as it is.&lt;/strong&gt;  There&#8217;s no way to directly access them from the home menu.  Your customers will have to open Safari, find their bookmark or manually type in the address, and login &#8230; username (or worse email) and password.  That&#8217;s a lot of navigating &#38; typing just to get into the application.  Hopefully Apple will develop quicker access methods, but until then the user experience has to be excellent to make it worthwhile to the customer.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;User interaction with an application on the iPhone is fundamentally different than other &#8220;screen&#8221; media types.&lt;/strong&gt;  We&#8217;re using our fingers, not a mouse.  Controls need to be big, finger-friendly and should take advantage of the tactile interactions that are by default a part of the user&#8217;s experience.  And don&#8217;t forget that all your hover and mouse-triggered javascript events will never be triggered.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;So assuming you&#8217;re building an application or enhancing an existing application to be competitive in the iPhone market, it makes sense to create an iPhone-specific UI. I&#8217;m working on a solution for Rails which will make tacking one on super simple which I&#8217;ll post shortly.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-06-01:4</id>
    <published>2007-06-01T21:08:00Z</published>
    <updated>2007-07-18T16:26:27Z</updated>
    <link href="http://blog.marcslove.com/2007/6/1/life-on-edge-rails-2006-06-01" rel="alternate" type="text/html"/>
    <title>Life on Edge Rails</title>
<content type="html">
            &lt;h4&gt;assert_difference &#38; assert_no_difference now accept an array of expressions&lt;/h4&gt;


	&lt;p&gt;The &lt;code&gt;assert_difference&lt;/code&gt; and &lt;code&gt;assert_no_difference&lt;/code&gt; testing methods now can accept an array of expressions to evaluate.  So now instead of doing:&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
assert_difference 'User.count', +1 do
  post :create, :article =&amp;gt; { :profile =&amp;gt; {}, ... }
end
assert_difference 'Profile.count', +1 do
  post :create, :article =&amp;gt; { :profile =&amp;gt; {}, ... }
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;we can do:&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
assert_difference ['User.count', 'Profile.count'], +1 do
  post :create, :article =&amp;gt; { :profile =&amp;gt; {}, ... }
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That&#8217;s some nice &lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt; action!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-05-31:2</id>
    <published>2007-05-31T20:00:00Z</published>
    <updated>2007-07-18T16:26:10Z</updated>
    <link href="http://blog.marcslove.com/2007/5/31/life-on-edge-rails-2007-05-31" rel="alternate" type="text/html"/>
    <title>Life on Edge Rails</title>
<content type="html">
            &lt;h4&gt;Date#change&lt;/h4&gt;


&lt;code&gt;Date&lt;/code&gt; now has &lt;code&gt;#change&lt;/code&gt; and works just like &lt;code&gt;Time#change&lt;/code&gt;.  So now we can do:

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;next_bill_date = Date.today.change( :month =&amp;gt; Date.today.month + 1, :day =&amp;gt; 15)
&lt;/code&gt;&lt;/pre&gt;

	&lt;h4&gt;All controller names pluralized&lt;/h4&gt;


&lt;code&gt;map.resource&lt;/code&gt; will now map to a pluralized controller name by default:

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;map.resource :account  # now maps to:
AccountsController &amp;lt; ApplicationController
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Where this makes even more sense to me is in this situation which I brought up in a &lt;a href=&quot;http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b55030e18e52bc98/805bfade50a63d47?lnk=gst&#38;q=Marc&#38;rnum=1#805bfade50a63d47&quot;&gt;post on the rubyonrails-core mailing list&lt;/a&gt; .  Let&#8217;s say I have products which each has_one manufacturer.  I want to be able to control those manufacturers both within the context of their association with the products and separately on their own.  The way it used to be:&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;map.resources :products, :has_one =&amp;gt; :manufacturer #=&amp;gt; ManufacturerController
map.resources :manufacturers #=&amp;gt; ManufacturersController&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The first mapping would look for a &lt;code&gt;ManufacturerController&lt;/code&gt; because &lt;code&gt;:has_one&lt;/code&gt; generates a singleton resource.  But the second mapping would look for a &lt;code&gt;ManufacturersController&lt;/code&gt;.  Regardless of the context, I&#8217;m probably going to control my manufacturers resource the same way.  So now all controllers are by default plural, whether its coming from &lt;code&gt;map:resource&lt;/code&gt;, &lt;code&gt;map.resources&lt;/code&gt;, &lt;code&gt;:has_one&lt;/code&gt;, or &lt;code&gt;:has_many&lt;/code&gt;.&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;map.resources :products, :has_one =&amp;gt; :manufacturer #=&amp;gt; ManufacturersController
map.resources :manufacturers #=&amp;gt; ManufacturersController&lt;/code&gt;&lt;/pre&gt;

	&lt;h4&gt;with_scope and with_exclusive_scope are now protected&lt;/h4&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.loudthinking.com/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;DHH&lt;/span&gt;&lt;/a&gt; has followed through on &lt;a href=&quot;http://groups.google.com/group/rubyonrails-core/msg/91ecfff96ae35de1&quot;&gt;his promise&lt;/a&gt; to make &lt;code&gt;with_scope&lt;/code&gt; a protected method and &lt;code&gt;with_exclusive_scope&lt;/code&gt; has come along for the ride.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-05-31:1</id>
    <published>2007-05-31T15:04:00Z</published>
    <updated>2007-07-18T16:25:38Z</updated>
    <link href="http://blog.marcslove.com/2007/5/31/measurements-extension" rel="alternate" type="text/html"/>
    <title>Ruby Measurements</title>
<content type="html">
            &lt;p&gt;Here&#8217;s something I&#8217;ve been working on&#8230;&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;Measurement.new(6,&quot;inches&quot;) == 6.inches

2.feet + 6.inches # =&amp;gt; == Measurement.new(2.5, &quot;feet&quot;)
6.5.feet - 18.inches # =&amp;gt; == Measurement.new(5, &quot;feet&quot;)
2.feet * 4 # =&amp;gt; == Measurement.new(8, &quot;feet&quot;)
4.feet / 2 # =&amp;gt; == Measurement.new(2, &quot;feet&quot;)
4.feet / 2.feet # =&amp;gt; == 2

2.inches &amp;gt; 2.centimeters #=&amp;gt; true
2.inches &amp;gt;= 2.centimeters #=&amp;gt; true
2.inches == 5.08.centimeters #=&amp;gt; true
5.inches.between?(3.inches, 6.inches) #=&amp;gt; true
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;More to come soon&#8230;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.marcslove.com/">
    <author>
      <name>Marc Love</name>
    </author>
    <id>tag:blog.marcslove.com,2007-05-30:3</id>
    <published>2007-05-30T16:10:00Z</published>
    <updated>2007-07-18T16:24:41Z</updated>
    <link href="http://blog.marcslove.com/2007/5/30/association-generated-methods-quick-reference" rel="alternate" type="text/html"/>
    <title>Association-generated methods quick reference</title>
<content type="html">
            &lt;p&gt;One of the &lt;a href=&quot;http://dev.rubyonrails.org/changeset/6905&quot;&gt;documentation patches I submitted last night&lt;/a&gt; was just accepted into the core.  It&#8217;s a quick reference table of the methods that are auto-generated when an association is created.&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;# ===Singular associations (one-to-one)
#                                     |            |  belongs_to  |
#   generated methods                 | belongs_to | :polymorphic | has_one
#   ----------------------------------+------------+--------------+---------
#   #other                            |     X      |      X       |    X
#   #other=(other)                    |     X      |      X       |    X
#   #build_other(attributes={})       |     X      |              |    X
#   #create_other(attributes={})      |     X      |              |    X
#   #other.create!(attributes={})     |            |              |    X
#   #other.nil?                       |     X      |      X       |    
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;# ===Collection associations (one-to-many / many-to-many)
#                                     |       |          | has_many
#   generated methods                 | habtm | has_many | :through  
#   ----------------------------------+-------+----------+----------
#   #others                           |   X   |    X     |    X
#   #others=(other,other,...)         |   X   |    X     |    
#   #other_ids                        |   X   |    X     |    
#   #other_ids=(id,id,...)            |   X   |    X     |    
#   #others&amp;lt;&amp;lt;                         |   X   |    X     |    X
#   #others.push                      |   X   |    X     |    X
#   #others.concat                    |   X   |    X     |    X
#   #others.build(attributes={})      |   X   |    X     |    X
#   #others.create(attributes={})     |   X   |    X     |    
#   #others.create!(attributes={})    |   X   |    X     |    X
#   #others.size                      |   X   |    X     |    
#   #others.length                    |   X   |    X     |    
#   #others.count                     |       |    X     |    
#   #others.sum(args*,&#38;block)         |   X   |    X     |    X
#   #others.empty?                    |   X   |    X     |    
#   #others.clear                     |   X   |    X     |    
#   #others.delete(other,other,...)   |   X   |    X     |    X
#   #others.delete_all                |   X   |    X     |    
#   #others.destroy_all               |   X   |    X     |    
#   #others.find(*args)               |   X   |    X     |    X
#   #others.find_first                |   X   |          |    
#   #others.uniq                      |   X   |    X     |    
#   #others.reset                     |   X   |    X     |    X
&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
</feed>
