Flowdock

Notes posted by RISCfuture

RSS feed
May 2, 2009
2 thanks

Re: Find random record

Ordering by RAND() is not a wise idea when you have a large table with lots of rows. Your database will have to calculate a different random value for every row in your database – O(N) – then sort the entire table by those values – O(N log N).

There are a number of better ways to get a random record from your table. Some examples:

  • If your table is not sparse, choose a random ID and get that row (or the nearest row):

rand_id = rand(Model.count)
rand_record = Model.first(:conditions => [ "id >= ?", rand_id]) # don't use OFFSET on MySQL; it's very slow
  • If your table is sparse, or does not have a primary key, consider adding an indexed column of random numbers between 0 and N. You can then order by this column quickly and choose a value using a method similar to the above example.

January 22, 2009
8 thanks

Using fields_for with has_many associations

If you want to edit each element of an array of objects (such as with a has_many type association), you will need to include “[]” in your field parameter name, like so:

<% fields_for "object[]" do |subfield| -%>
  [...]
 <% end -%>

Because you named the field parameter “object[]”, fields_for will assume you have an instance variable @object to use for the fields’ values. To fake this, you can do something like:

<% objects.each do |@object| -%>
  <% fields_for "object[]" do |subfield| -%>
    [...]
  <% end -%>
<% end -%>

If that looks like sacrilegious Rails code to you, then you could consider:

<% objects.each do |object| -%>
  <% fields_for "object[]", object do |subfield| -%>
    [...]
  <% end -%>
<% end -%>

In either case, params[:object] will be a hash where the ID of each object (determined via ActiveRecord::Base#to_param ) is associated with a hash of its new values:

params = { 'object' => { '123' => { 'field' => 'newval' }, '159' => { 'field' => 'newval' } } }
January 14, 2009
6 thanks

File open permissions

Usage: File.open path, flags, [permissions]

Flags (bitmasks)

Access:

File::RDONLY

Read-only

File::WRONLY

Write-only

File::RDWR

Read and write

If the file exists:

File::TRUNC

Truncate

File::APPEND

Append

File::EXCL

Fail

If the file doesn’t exist:

File::CREAT

Create

Flags (strings)

r

File::RDONLY

r+

File::RDWR

w

File::WRONLY|File::TRUNC|File::CREAT

a

File::WRONLY|File::APPEND|File::CREAT

Examples

File.open path, File::RDONLY
File.open path, 'w'
File.open path, File::WRONLY|File::TRUNC|File::CREAT
File.open path, File::WRONLY|File::TRUNC|File::CREAT, '0666'
December 11, 2008 - (>= v1.0.0)
5 thanks

Calling migrations within migrations

It’s very occasionally a wise strategy to call migrations from within other migrations. This is typically done when you are adding a migration that deletes a now-obsolete table.

Let’s say one night when you were drunk or otherwise not thinking straight you did something like this:

class CreateExGirlfriendTexts < ActiveRecord::Migration
  def self(dot)up
    create_table :ex_girlfriend_texts { |t| ... }
  end

  def self(dot)down
    drop_table :ex_girlfriend_texts
  end
end

Oops! You could add this for your “undo” migration the next morning:

class FixDrunkMistake < ActiveRecord::Migration
  def self(dot)up
    CreateExGirlfriendTexts.down
  end

  def self(dot)down
    CreateExGirlfriendTexts.up
  end
end

Now, in the event you decide you really did like that table, you can always get it back easily. Keep in mind this will be made more complicated if your table is modified over multiple transactions.

December 11, 2008
6 thanks

Accessing aggregate methods with :group

You can access aggregate methods (such as SUM, COUNT, etc.) when using a JOIN and GROUP BY query by simply naming the aggregate columns and calling them as methods on the returned objects:

hits_by_page = WebpageHit.all({
  :select => "webpages.*, COUNT(webpage_hit.id) AS view_count",
  :joins => :webpage,
  :group => "webpages.id"
})
homepage_hits = hits_by_page[homepage.id].view_count

The view_count method is added to the Webpage model by this call. Note, however, that this method returns a string, and is not typecasted by Rails.

October 22, 2008
2 thanks

Regenerate the JavaScript after each RJS call

I had a sortable_element that was also a drop_receiving_element. After an element was dropped onto this div, an RJS action refreshed the div with the new elements. The div expanded with these new elements, but the sortable portion remained the same size.

To correctly be able to reorder elements after an Element.update call (from an RJS action or wherever), you need to include a second call to Sortable.create in your RJS view (or other JavaScript), using sortable_element_js or whatever method you please.