ActiveRecord.find_each_with_order = find_each with order…

I just hate things that fail silently, just like User.order_by(:created_at).find_each

Which will simply ignore the order option….

So here comes the alternative…

class ActiveRecord::Base
  # normal find_each does not use given order but uses id asc
  def self.find_each_with_order(options={})
    raise "offset is not yet supported" if options[:offset]

    page = 1
    limit = options[:limit] || 1000

    loop do
      offset = (page-1) * limit
      batch = find(:all, options.merge(:limit => limit, :offset => offset))
      page += 1

      batch.each{|x| yield x }

      break if batch.size < limit
    end
  end
end

(the ๐Ÿ˜ฎ is : and o)

Unobstrusive word_wrap aka split_after for Ruby / Rails

Evil users often write something like “SomeThingNewAndGreat,use,it aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa” just to annoy us developers who try to get their content into a 50x100px div (at least I suspect it…).

Usage
(Use it after truncating, since it adds additional characters)

#!invisible char between 6 and 7!
"12345 12345678".split_after(3) == "12345 123456โ€‹78"
"12345 12345678".split_after(6, :with=>'<br />') == "12345 123456<br />78"

Code

  # splits to long words after max chars with invisible "zero-length-space"
  # UTF8 char that should display in all browsers
  # http://www.fileformat.info/info/unicode/char/200b/index.htm
  def split_after(max, options={})
    zero_length_space = 'โ€‹' #aka โ€‹
    options[:with] ||= zero_length_space

    split(/ /).map do |part|
      part = part.mb_chars
      if part.length > max
        part[0...max] + options[:with] + part[max..-1].to_s.split_after(max)
      else
        part
      end
    end * ' '
  end

How to Preview All ActionMailer Mails in the Browser

Notice: this needs to be admin/development only, since it can be really dangerous in the wrong hands… (uses eval or param…)

  • Developers see what they are dooing (just hit Refresh)
  • Livesaver for HTML Emails
  • Non-developers can check alignment/spelling/… sooo easy
  • Generated mails can be shared through url so no need for forwarding/screenshots

View
Just make a form that submits:

  • the method you want to call
  • list of arguments to use
  <%form_tag({:action=>'make_mail'}, :method=>:get) do%>
    <%=select_tag :method_name, options_for_select(UserMailer.public_instance_methods(false).sort)%>
    Models: Product.find(12322) / String: "abc" / Numbers: 123 / Array: [1,2,3]
    <table>
      <%5.times do |i|%>
        <tr>
          <td><%=i%></td>
          <td><%=text_field_tag "args[]", '', :style=>'width:300px'%></td>
        </tr>
      <%end%>
    </table>
    <%=submit_tag 'Preview'%>
    <%=submit_tag 'Send'%>
  <%end%>
<%end%>

Controller
Evals the ‘args’ and send or previews the mail.

def make_mail
  args = params[:args].map{|arg| eval arg}.compact

  if params[:commit]=='Preview' #preview button
    @text = UserMailer.send("create_#{params[:method_name]}", *args).body
    if @text =~ /<body>/
      render :text=>@text
    else
      render :text=>"<pre>#{@text}</pre>"
    end
  else #Send button
    UserMailer.send("deliver_#{params[:method_name]}", *args)
    flash[:notice] = 'Mail sent!'
    redirect_to params.merge(:action=>:index)
  end
end

Happy mail preview too you ๐Ÿ˜€