<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Binary Logic &#187; ruby</title>
	<atom:link href="http://www.binarylogic.com/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.binarylogic.com</link>
	<description>Ben Johnson's thoughts and programming techniques</description>
	<lastBuildDate>Sat, 23 Jan 2010 21:19:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Introducing Shippinglogic</title>
		<link>http://www.binarylogic.com/2009/08/07/introducing-shippinglogic/</link>
		<comments>http://www.binarylogic.com/2009/08/07/introducing-shippinglogic/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 23:59:29 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Shippinglogic]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.binarylogic.com/?p=774</guid>
		<description><![CDATA[Today I released the first version of Shippinglogic, which is a ruby library I wrote to make integrating with FedEx, UPS, USPS, etc, very easy.
This is not a project I wanted to do, but I couldn&#8217;t find a library that did everything I needed it to. One library had support for creating shipments, but didn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>Today I released the first version of <strong><a href="http://github.com/binarylogic/shippinglogic/tree/master" target="_blank">Shippinglogic</a></strong>, which is a ruby library I wrote to make integrating with FedEx, UPS, USPS, etc, very easy.</p>
<p>This is not a project I wanted to do, but I couldn&#8217;t find a library that did everything I needed it to. One library had support for creating shipments, but didn&#8217;t have support for getting a list of rates. Another had support for getting rates, but didn&#8217;t have support for creating shipments. I need both for the application I&#8217;m working on. I even decided to modify one of the libraries to suit my needs but the code was really hard to follow and I didn&#8217;t feel comfortable using it. Especially since shipping was such an important part of my application.</p>
<p>That&#8217;s when I came to the sad realization that I probably need to write my own library.<span id="more-774"></span> I was really surprised by the lack of choices when it came to shipping API integration. Then I started reading the FedEx documentation and realized why. Documentation on creating a shipment with the FedEx web services was 570 pages long. The amount of bullshit in the documentation astounded me. 99% of developers are probably concerned with maybe 30 pages in that entire document. I felt like I was reading a legal document, not web service documentation.</p>
<p>Sorry for the ranting, but this week has been especially frustrating, imagine reading FedEx documentation all day. Anyways, onto <strong><a href="http://github.com/binarylogic/shippinglogic/tree/master" target="_blank">Shippinglogic</a></strong>.</p>
<h3>What is Shippinglogic?</h3>
<p>My goal with <strong><a href="http://github.com/binarylogic/shippinglogic/tree/master" target="_blank">Shippinglogic</a></strong> was to make integrating with the various shipping APIs (FedEx, UPS, USPS, etc) easy and <strong>complete</strong>. The keyword being complete. Shippinglogic is not an abstraction layer, meaning each classes&#8217; focus is on the web service at hand. It is not trying to conform to an interface. With all of the differences between the various APIs its simply not possible to do this without severely limiting the feature sets for each API. There is no defined shipping standard that all of these companies agreed on, so how do you safely make an abstraction layer for this?</p>
<p>Anyways, I think it turned out pretty well. The syntax is pretty slick, thanks to the <a href="http://www.binarylogic.com/2009/08/07/how-to-create-a-proxy-class-in-ruby">proxy class trick I talked about in a previous post</a>.</p>
<p>Here&#8217;s a quick example of tracking a package:</p>
<pre class="ruby">
fedex = Shippinglogic::FedEx.new(key, password, account, meter)
tracking = fedex.track(:tracking_number => "XXXXXXXXXXXXXXXXX")

# this shows that the tracking object is actually a proxy for the underlying array
tracking.tracking_number
# => "XXXXXXXXXXXXXXXXX"

tracking.tracking_number = "YYYYYYYYYYYYYYY"
# => "YYYYYYYYYYYYYYY"

tracking.class
# => Array

tracking.first
# => #<Shippinglogic::FedEx::Track::Event @postal_code="95817", @name="Delivered", @state="CA", @residential=false,
#    @city="Sacramento", @type="DL", @country="US", @occured_at=Mon Dec 08 10:43:37 -0500 2008>

tracking.first.name
# => "Delivered"
</pre>
<p>I was pretty thorough with the documentation. Check out the <a href="http://github.com/binarylogic/shippinglogic/tree/master" target="_blank">project on github</a> for more examples. Let me know what you think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2009/08/07/introducing-shippinglogic/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>How to create a proxy class in ruby</title>
		<link>http://www.binarylogic.com/2009/08/07/how-to-create-a-proxy-class-in-ruby/</link>
		<comments>http://www.binarylogic.com/2009/08/07/how-to-create-a-proxy-class-in-ruby/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 23:53:31 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[proxy]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.binarylogic.com/?p=775</guid>
		<description><![CDATA[Creating a proxy class in ruby can be a nice tool to have in your nerdy tool belt, and its actually really simple to do. Have you ever wondered how ActiveRecord is able to pull off its nifty tricks with associations? Ex:

user = User.first
user.orders.build
# => #Order object

user.orders.first
# => #Order ojbect

user.orders.class
# => Array

Wait, &#8216;build&#8217; isn&#8217;t a [...]]]></description>
			<content:encoded><![CDATA[<p>Creating a proxy class in ruby can be a nice tool to have in your nerdy tool belt, and its actually really simple to do. Have you ever wondered how ActiveRecord is able to pull off its nifty tricks with associations? Ex:</p>
<pre class="ruby">
user = User.first
user.orders.build
# => #Order object

user.orders.first
# => #Order ojbect

user.orders.class
# => Array
</pre>
<p>Wait, &#8216;build&#8217; isn&#8217;t a method available for arrays. How did they do that?<span id="more-775"></span></p>
<p>One way is to add a &#8216;build&#8217; method into the Array class, but this is really intrusive. You don&#8217;t necessarily need a build method for every Array object, more importantly build needs to know what kind of object to build. How does it get this information?</p>
<p>The answer to the mystery is a proxy class that delegates method calls to the underlying array. It&#8217;s actually really simple to do. Check it out:</p>
<pre>
class Proxy
    instance_methods.each { |m| undef_method m unless m =~ /(^__|^send$|^object_id$)/ }

    def my_awesome_method
       "you just called an awesome method!"
    end

    protected
        def method_missing(name, *args, &#038;block)
          target.send(name, *args, &#038;block)
        end

        def target
          @target ||= []
        end
end
</pre>
<p>Notice that the first thing we do is undefine just about every method in the class. This makes sure that calls to those methods hit method_missing and ultimately get called on the underlying array. Afterwards we define any special methods, such as &#8216;my_awesome_method&#8217;, and then we handle any calls to undefined methods. That&#8217;s it! It&#8217;s actually really simple and clever. Here&#8217;s how it works:</p>
<pre>
proxy = Proxy.new
proxy.my_awesome_method
# => "you just called an awesome method!"

proxy.class
# => Array
</pre>
<h3>Why would you want to do this?</h3>
<p>Well sometimes you want to add a little extra functionality to a basic object, such as an Array, Hash, etc. This allows you to do that without having to modify the underlying class, which is good. You basically get to play middle man and intercept any calls to that object. Then you have the decision to pass them through or do your own thing. This also promotes much more &#8220;ruby like&#8221; syntax. Without this, calling associations in AR would look something like:</p>
<pre>
user.orders.build
user.orders.create
user.orders.all.first
user.orders.all.size
</pre>
<p>Anything related to the underlying Array must be called off of the &#8220;all&#8221; method. That just seems dirty. This is so much cleaner:</p>
<pre>
user.orders.build
user.orders.create
user.orders.first
user.orders.size
</pre>
<p>Pretty cool huh?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2009/08/07/how-to-create-a-proxy-class-in-ruby/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Searchlogic v2 officially released</title>
		<link>http://www.binarylogic.com/2009/06/15/searchlogic-v2-officially-released/</link>
		<comments>http://www.binarylogic.com/2009/06/15/searchlogic-v2-officially-released/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 06:14:47 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Searchlogic]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[v2]]></category>

		<guid isPermaLink="false">http://www.binarylogic.com/?p=768</guid>
		<description><![CDATA[Tonight I went ahead and officially released searchlogic v2. If you didn&#8217;t read my last post, v2 is a complete rewrite of the library. It takes a new approach. It went from ~2300 lines of code to ~400 lines of code. It&#8217;s simpler, easier to use, much more light weight, faster, and more importantly, easier [...]]]></description>
			<content:encoded><![CDATA[<p>Tonight I went ahead and officially released <a href="http://github.com/binarylogic/searchlogic/tree/master">searchlogic v2</a>. If you didn&#8217;t read my last post, v2 is a <em>complete</em> rewrite of the library. It takes a new approach. It went from ~2300 lines of code to ~400 lines of code. It&#8217;s simpler, easier to use, much more light weight, faster, and more importantly, easier to maintain, understand, and improve upon.</p>
<p>I&#8217;m not going to ramble about the changes, because you can read my <a hef="http://www.binarylogic.com/2009/06/09/searchlogic-v2-beta-released/">previous post</a> or you can check out the <a href="http://github.com/binarylogic/searchlogic/tree/master">read me</a> on github.</p>
<h3>Using github not rubyforge</h3>
<p>I have decided to start using github to host my gems, if you want to start using v2 as a gem you need to install the binarylogic-searchlogic gem from the github source. (checkout the <a href="http://github.com/binarylogic/searchlogic/tree/master">read me</a> for easy installation instructions).</p>
<h3>Thank you</h3>
<p>Sorry for such a quick post. I figured this was an important announcement.</p>
<p>Thank you for being patient with v1, I know there were some people having issues. This should address all of them.</p>
<p>As always, I did my best with the <a href="http://github.com/binarylogic/searchlogic/tree/master">readme</a> and the <a href="http://rdoc.info/projects/binarylogic/searchlogic">rdocumentation</a>. If you really want to see what v2 is all about I suggest you take a glance at those, they should be comprehensive.</p>
<p>I hope you enjoy v2, I&#8217;m really excited to release it. I have already integrated it into the app that I am working on, and I love it. It works great and all of my tests pass.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2009/06/15/searchlogic-v2-officially-released/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Searchlogic v2 beta released</title>
		<link>http://www.binarylogic.com/2009/06/09/searchlogic-v2-beta-released/</link>
		<comments>http://www.binarylogic.com/2009/06/09/searchlogic-v2-beta-released/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 04:07:14 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Searchlogic]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[v2]]></category>

		<guid isPermaLink="false">http://www.binarylogic.com/?p=756</guid>
		<description><![CDATA[Searchlogic v2 beta was released today, it is a complete rewrite of the library, no code was reused. Right now its in a separate branch under the Searchlogic project, and will be merged when it is taken out of beta status. Let me explain how it&#8217;s different.
So, the project I&#8217;m working on now required something [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/binarylogic/searchlogic/tree/v2">Searchlogic v2 beta</a> was released today, it is a <strong>complete</strong> rewrite of the library, no code was reused. Right now its in a separate branch under the <a href="http://github.com/binarylogic/searchlogic/tree/master">Searchlogic project</a>, and will be merged when it is taken out of beta status. Let me explain how it&#8217;s different.</p>
<p>So, the project I&#8217;m working on now required something from Searchlogic v1 that it couldn&#8217;t provide. That is, searching with existing named scopes. I could do this, but it wasn&#8217;t as elegant as it was with the built in conditions (Ex: username_like, etc.).</p>
<h2>The idea behind Searchlogic v2</h2>
<p>So this got me thinking, how can I get Searchlogic v1 to use existing named scopes? That&#8217;s when it hit me, why not use named scopes for everything?<span id="more-756"></span>I think we can all agree named scopes are the heart of searching and breaking up common search logic in your models. Instead of having all of this crazy logic write SQL and chain it together, as in v1, why not have Searchlogic dynamically create these common named scopes for you and then just leverage those? That&#8217;s exactly what v2 does. Instead of going into detail about v2, check out the <a href="http://github.com/binarylogic/searchlogic/tree/v2">current README</a>. It explains everything v2 has to offer up to this point.</p>
<p>The best part about this approach is that it fits nicely into your application. All that it is doing is creating named scopes. More importantly, if you need some condition that Searchlogic doesn&#8217;t offer, no problem, just create your own named scope. This is what you should be doing anyways.</p>
<p>To bring it all home, let me show a simple search form that uses v2. Assume we have</p>
<pre>
User(name:string, age:integer)
Order(user_id:integer, total:float)

User.has_many :orders
User.named_scope :four_year_olds, :conditions => {:age => 4}
User.named_scope :name_sounds_like, lamda { |value| {:conditions => ["name SOUNDS LIKE ?", value]} }
</pre>
<p>Your search form could look like this:</p>
<pre class="ruby">
- form_for @search do |f|
  = f.text_field :name_like
  = f.select :age_greater_than, (1..100)
  = f.text_field :orders_total_less_than
  = f.text_field :name_sounds_like
  = f.check_box :four_year_olds
  = f.submit
</pre>
<p>Notice the use of custom named scopes. Also the other conditions are also named scopes that searchlogic dynamically defines as you need them.</p>
<h2>The best part of v2</h2>
<ul>
<li><strong>V1:</strong> ~2300 lines of code</li>
<li><strong>V2:</strong> ~350 lines of code</li>
</ul>
<p>As you might have saw <a href="http://www.binarylogic.com/2009/04/17/need-some-help-searchlogic-20/">in this post</a> Searchlogic v1 was too big for me to handle. The issues people were having would take way too long to solve and I just didn&#8217;t like the code. The library really wasn&#8217;t advancing and it was just an annoyance. It was regretably the first library I ever wrote, and as such there are a lot of things I would do differently, which should be evident in v2.</p>
<p>That being said, v2 is lean, makes sense, and just feels right. I&#8217;m really looking forward to maintaing the library and seeing where it goes. I hope everyone enjoys it. Let me know what you think. There are just a couple of things left to do before I officially release it.</p>
<h2>Applications using v1</h2>
<p>Lastly, because this is such a big change, backwards compatibility <em>will</em> be broken. Before I officially release the library I will write a document explaining the differences and how to transition. In the mean time, your gem declarations in your application should look like this, so that your app doesn&#8217;t break when the new version is released:</p>
<pre>
 config.gem "searchlogic", :version => "~> 1.6.6"
# the ~ will let you advance minor and tiny versions, but not major versions.
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2009/06/09/searchlogic-v2-beta-released/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Authlogic shares the love, merb support added</title>
		<link>http://www.binarylogic.com/2008/11/05/authlogic-shares-the-love-merb-support-added/</link>
		<comments>http://www.binarylogic.com/2008/11/05/authlogic-shares-the-love-merb-support-added/#comments</comments>
		<pubDate>Wed, 05 Nov 2008 19:06:00 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Authlogic]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[merb]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">0/2009/03/23/authlogic-shares-the-love-merb-support-added</guid>
		<description><![CDATA[Rails doesn&#8217;t have to hog all of the Authlogic love, it&#8217;s time to start sharing. So I decided to send a little love to the merb peeps and add in a merb adapter. Just install the Authlogic gem and include it as a dependency and you are good to go. Authentication in your app is [...]]]></description>
			<content:encoded><![CDATA[<p>Rails doesn&#8217;t have to hog all of the <a href="http://github.com/binarylogic/authlogic">Authlogic</a> love, it&#8217;s time to start sharing. So I decided to send a little love to the merb peeps and add in a merb adapter. Just install the <a href="http://github.com/binarylogic/authlogic">Authlogic</a> gem and include it as a dependency and you are good to go. Authentication in your app is as easy as setting up a resource for a model.</p>
<p>I think this is just the beginning though, here are my thoughts&#8230;.</p>
<p>            <span id="more-163"></span></p>
<h2>The Big Picture</h2>
<p>Thanks to things like <a href="http://rack.rubyforge.org/">Rack</a>, the MVC design pattern, and ActiveRecord / DataMapper, all of these frameworks look very similar. They all have a similar pattern, which is the inherent nature of the MVC design pattern. So I decided to take advantage of this with Authlogic. Any specific framework implementation is extracted out into an adapter. Similar to how ActiveRecord has an adapter for each database type, except the Authlogic adapters are much simpler.</p>
<p>Probably the main reason these adapters are so simple / similar is because of Rack. Thanks to Rack, there is a request standard across all of these frameworks. &#8220;But Ben, why not skip all of this nonsense and implement this right into Rack?&#8221;. The reason I didn&#8217;t go right into Rack is&#8230;</p>
<ol>
<li>Not every &#8220;Rack compatible&#8221; framework uses the Rack libraries. After digging through the rails internals I found that the RackRequest class extends AbstractRequest, which has nothing to do with Rack. Lastly, older versions of rails aren&#8217;t rack compatible.</li>
<li>I need to hook into the controller anyways with a before_filter</li>
<li>With my implementation you get the best of both worlds. I designed the AbstractAdapter to conform to the rack standards, and any framework specific implementation can subclass this and do it&#8217;s magic.</li>
</ol>
<p>So what&#8217;s the big picture here? The big picture is that there is no reason Authlogic can&#8217;t be an authentication solution for virtually any ruby framework out there. Why reinvent the wheel for every framework?</p>
<h2>What about framework X?</h2>
<p>Since writing adapters for rails and merb was so simple, why not keep going? Here are a few frameworks I plan to write an adapter for:</p>
<ol>
<li><a href="http://www.mackframework.com/">Mack</a></li>
<li><a href="http://ramaze.net/">Ramaze</a></li>
<li><a href="http://sinatra.rubyforge.org/">Sinatra</a></li>
</ol>
<p>If you are feeling generous and want to write an adapter for a framework other than rails or merb, please do so. Let me know about it and I will add it into the source.</p>
<h2>Final thoughts</h2>
<p>Authlogic loves you regardless of your framework</p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2008/11/05/authlogic-shares-the-love-merb-support-added/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Searchlogic 1.3.0 &#8211; Adding modifiers into the mix</title>
		<link>http://www.binarylogic.com/2008/10/02/searchlogic-1-3-0-adding-modifiers-into-the-mix/</link>
		<comments>http://www.binarylogic.com/2008/10/02/searchlogic-1-3-0-adding-modifiers-into-the-mix/#comments</comments>
		<pubDate>Thu, 02 Oct 2008 12:40:00 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Searchlogic]]></category>
		<category><![CDATA[modifiers]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[searchgasm]]></category>

		<guid isPermaLink="false">0/2009/03/23/searchlogic-1-3-0-adding-modifiers-into-the-mix</guid>
		<description><![CDATA[Searchlogic 1.3.0 was released today and has some pretty cool features, mainly modifiers. I&#8217;m going to assume you know what Searchlogic is. If you don&#8217;t, you&#8217;re missing out. Take a quick glance at the readme on github, otherwise this article probably won&#8217;t make a whole lot of sense.
        [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/binarylogic/searchlogic">Searchlogic 1.3.0</a> was released today and has some pretty cool features, mainly modifiers. I&#8217;m going to assume you know what <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a> is. If you don&#8217;t, you&#8217;re missing out. Take <a href="http://github.com/binarylogic/searchlogic">a quick glance at the readme</a> on github, otherwise this article probably won&#8217;t make a whole lot of sense.</p>
<p>            <span id="more-44"></span></p>
<h2>Why modifiers are necessary?</h2>
<p>ActiveRecord does a great job when it comes to keeping your code database agnostic. But I feel like it neglected searching when it came to that goal. What if you want to find all records that were created after 7am? Depending on your database you would have to do something like the following:</p>
<pre><code>MySQL:        HOUR(created_at)
PostgreSQL:   date_part('hour', created_at)
SQLite:       strftime('%H', created_at)
</code></pre>
<p>All of a sudden your app is not database agnostic. Oh no!</p>
<p>All of that bragging to your girlfriend about how you can switch databases in a matter of minutes was all a lie. How&#8217;s she going to feel when she finds out HOUR(created_at) is a MySQL specific function? Searchlogic to the rescue!</p>
<h2>Searchlogic modifiers</h2>
<p>Remember how you can do this in searchlogic?</p>
<pre class="cobalt">
<span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span><span class="Punctuation">(</span><span class="Constant"><span class="Punctuation">:</span>condition</span> <span class="Punctuation">=&gt;</span> <span class="Punctuation">{</span><span class="Constant"><span class="Punctuation">:</span>created_at_gt</span> <span class="Punctuation">=&gt;</span> <span class="Support">Time</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">parse</span></span><span class="Punctuation">(</span><span class="String"><span class="Punctuation">&quot;</span>Jan 1, 2008<span class="Punctuation">&quot;</span></span><span class="Punctuation">)</span><span class="Punctuation">}</span><span class="Punctuation">)</span>
<span class="Comment"><span class="Punctuation">#</span> =&gt; &quot;created_at &gt; 2008-01-01 00:00:00</span>
</pre>
<p>Now you can do this too:</p>
<pre class="cobalt">
<span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span><span class="Punctuation">(</span><span class="Constant"><span class="Punctuation">:</span>conditions</span> <span class="Punctuation">=&gt;</span> <span class="Punctuation">{</span><span class="Constant"><span class="Punctuation">:</span>hour_of_created_at_gt</span> <span class="Punctuation">=&gt;</span> <span class="Constant">10</span><span class="Punctuation">}</span><span class="Punctuation">)</span>
<span class="Comment"><span class="Punctuation">#</span> =&gt; HOUR(created_at) &gt; 10</span>
</pre>
<p>or this:</p>
<pre class="cobalt">
<span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span><span class="Punctuation">(</span><span class="Constant"><span class="Punctuation">:</span>conditions</span> <span class="Punctuation">=&gt;</span> <span class="Punctuation">{</span><span class="Constant"><span class="Punctuation">:</span>tan_of_sin_of_cos_of_minute_of_created_at_gt</span> <span class="Punctuation">=&gt;</span> <span class="Constant">20</span><span class="Punctuation">}</span><span class="Punctuation">)</span>
<span class="Comment"><span class="Punctuation">#</span> =&gt; TAN(SIN(COS(MINUTE(created_at)))) &gt; 20</span>
</pre>
<p>What the hell was that? That was me making the point that you can chain modifiers. Obviously a very unrealistic example, but cool none-the-less.</p>
<p><a href="http://github.com/binarylogic/searchlogic">Check out the readme for a list of modifiers</a> and <a href="http://github.com/binarylogic/searchlogic/tree/master/CHANGELOG.rdoc">check out the changelog for a complete list of changes</a></p>
<p>What do you think?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2008/10/02/searchlogic-1-3-0-adding-modifiers-into-the-mix/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Tutorial: Pagination, ordering, and searching with Searchlogic</title>
		<link>http://www.binarylogic.com/2008/09/07/tutorial-pagination-ordering-and-searching-with-searchlogic/</link>
		<comments>http://www.binarylogic.com/2008/09/07/tutorial-pagination-ordering-and-searching-with-searchlogic/#comments</comments>
		<pubDate>Sun, 07 Sep 2008 01:05:00 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Searchlogic]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[ordering]]></category>
		<category><![CDATA[pagination]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[searchgasm]]></category>
		<category><![CDATA[searching]]></category>

		<guid isPermaLink="false">0/2009/03/23/tutorial-pagination-ordering-and-searching-with-searchlogic</guid>
		<description><![CDATA[Paginating, ordering, searching &#8211; no longer a pain in the ass
Maybe it&#8217;s not a pain in the ass for you, maybe it is, or maybe it is and you don&#8217;t know it. We&#8217;ll never know. Either way, this tutorial is pain-in-the-ass free. Guaranteed. That&#8217;s what this is all about, making your life easier when it [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Paginating, ordering, searching &#8211; no longer a pain in the ass</strong></p>
<p>Maybe it&#8217;s not a pain in the ass for you, maybe it is, or maybe it is and you don&#8217;t know it. We&#8217;ll never know. Either way, this tutorial is pain-in-the-ass free. Guaranteed. That&#8217;s what this is all about, making your life easier when it comes to paginating, ordering, and searching. Things you do multiple times in almost every application.</p>
<p>My solution: <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a>. It has saved me a lot time, shortened my code, and ultimately given me the proper tools to paginate, order, and search my data. Hopefully it will do the same for you.</p>
<p>            <span id="more-13"></span></p>
<p>Enough talk, let&#8217;s dive in.</p>
<p>&#8220;Does this really work? Am I about to waste my time?&#8221;. I hope not. But just for you, I made this live example:</p>
<h3><a href="http://searchlogic_example.binarylogic.com">Live example based on this tutorial</a></h3>
<p>Paginating, ordering, and searching doesn&#8217;t get any easier than this. Before we start I want to make the following assumptions about you:</p>
<ol>
<li>You have a working rails application on rails edge (rake rails:freeze:edge)</li>
<li>You have the following model structure: UserGroup =&gt; User =&gt; Order (=&gt; = has_many). Make sure you have the has_many and belongs_to relationships set up. The fields are irrelevant, just change the field names in the view to whatever you have.</li>
</ol>
<div class="spacer5"></div>
<h2>1. Install <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a></h2>
<pre class="cobalt">
$ sudo gem install searchlogic
</pre>
<p>Now add the gem dependency to your rails config:</p>
<pre class="cobalt">
<span class="Comment"><span class="Punctuation">#</span> config/environment.rb</span>
config<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">gem</span></span> <span class="String"><span class="Punctuation">&quot;</span>searchlogic<span class="Punctuation">&quot;</span></span>
</pre>
<p>As always you can install searchlogic as a plugin, but plugins are becoming a thing of the past. I recommend the above approach, but here is the plugin installation if you prefer to do it this way:</p>
<pre class="cobalt">
$ script/plugin install git://github.com/binarylogic/searchlogic.git
</pre>
<div class="spacer5"></div>
<h2>2. Create your controller</h2>
<p>Let&#8217;s create a controller that searches, orders, and paginates users. Like an admin area. Create app/controllers/users_controller.rb with the following content:</p>
<pre class="cobalt">
<span class="Comment"><span class="Punctuation">#</span> app/controllers/users_controller.rb</span>
<span class="Keyword">class</span> <span class="Entity">UsersController<span class="EntityInheritedClass"> <span class="Punctuation">&lt;</span> ApplicationController</span></span>
    <span class="Keyword">def</span> <span class="Entity">index</span>
        <span class="Variable"><span class="Punctuation">@</span>search</span> <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">new_search</span></span><span class="Punctuation">(</span>params<span class="Punctuation">[</span><span class="Constant"><span class="Punctuation">:</span>search</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
        <span class="Variable"><span class="Punctuation">@</span>users</span><span class="Punctuation">,</span> <span class="Variable"><span class="Punctuation">@</span>users_count</span> <span class="Keyword">=</span> <span class="Variable"><span class="Punctuation">@</span>search</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span><span class="Punctuation">,</span> <span class="Variable"><span class="Punctuation">@</span>search</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">count</span></span>
    <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<h3>What did we do here?</h3>
<p>It&#8217;s simple actually, if you haven&#8217;t looked at <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a> I suggest you take a quick glance. I&#8217;m not going to get into crazy detail about what it does, because the README in the library covers that, but to make this short it &#8220;enhances&#8221; searching with ActiveRecord.</p>
<p>Notice that we started a new search with the @search object. This lets you search via an object, which is really handy for your view, which you will see below. It also added in some nifty methods such as page, per_page, order_by, order_as, and a plethora of conditions for each of your columns. The second line does a simple search and counts the results. The thing to remember here is that the .count method ignores pagination. It ignores the limit and offset values. So if you want to know how many users matched the search, use count, not @users.size. If the first page is limited to 10 reconds @user.size will return 10.</p>
<div class="spacer5"></div>
<h2>3. Create the view and your&#8217;re done</h2>
<pre class="cobalt">
# app/views/users/index.html.erb
<span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">if</span> <span class="Variable"><span class="Punctuation">@</span>users_count</span> <span class="Keyword">&gt;</span> <span class="Constant">0</span> <span class="Punctuation">%&gt;</span></span>
    <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> <span class="Variable"><span class="Punctuation">@</span>users_count</span> <span class="Punctuation">%&gt;</span></span> users found

    <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">table</span> <span class="MetaTagA">border</span>=<span class="String"><span class="Punctuation">&quot;</span>1<span class="Punctuation">&quot;</span></span> <span class="MetaTagA">cellpadding</span>=<span class="String"><span class="Punctuation">&quot;</span>5<span class="Punctuation">&quot;</span></span><span class="Punctuation">&gt;</span></span>
        <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">tr</span><span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> order_by_link <span class="Constant"><span class="Punctuation">:</span>id</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> order_by_link <span class="Constant"><span class="Punctuation">:</span>user_group</span> <span class="Punctuation">=&gt;</span> <span class="Constant"><span class="Punctuation">:</span>name</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> order_by_link <span class="Constant"><span class="Punctuation">:</span>first_name</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> order_by_link <span class="Constant"><span class="Punctuation">:</span>last_name</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> order_by_link <span class="Punctuation">[</span><span class="Constant"><span class="Punctuation">:</span>email</span><span class="Punctuation">,</span> <span class="Constant"><span class="Punctuation">:</span>first_name</span><span class="Punctuation">]</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">th</span><span class="Punctuation">&gt;</span></span>
        <span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">tr</span><span class="Punctuation">&gt;</span></span>
        <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Variable"><span class="Punctuation">@</span>users</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">each</span></span> <span class="Keyword">do </span><span class="Punctuation">|</span><span class="Variable">user</span><span class="Punctuation">|</span> <span class="Punctuation">%&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">tr</span><span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">id</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">user_group</span></span> <span class="Keyword">?</span> user<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">user_group</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">name</span></span> <span class="Punctuation">:</span> <span class="String"><span class="Punctuation">&quot;</span>-<span class="Punctuation">&quot;</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">first_name</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">last_name</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span><span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">email</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">td</span><span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">tr</span><span class="Punctuation">&gt;</span></span>
        <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>
    <span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">table</span><span class="Punctuation">&gt;</span></span>

    <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
    <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>

    Per page: <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> per_page_select <span class="Punctuation">%&gt;</span></span>

    <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">if</span> <span class="Variable"><span class="Punctuation">@</span>search</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">page_count</span></span> <span class="Keyword">&gt;</span> <span class="Constant">1</span> <span class="Punctuation">%&gt;</span></span>
        <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>Page: <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> page_select <span class="Punctuation">%&gt;</span></span>
    <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>
<span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">else</span> <span class="Punctuation">%&gt;</span></span>
    No users were returned
<span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>
</pre>
<h3>What did we do here?</h3>
<p>All that we did was iterate through our users, list them in a table format, and then add page and per_page controls. Notice any unusual helpers? (order_by_link, per_page_select, and page_select). I won&#8217;t go into detail about these helpers because its all <a href="http://searchlogic.rubyforge.org">in the documentation</a> under Searchlogic::Helpers::ControlTypes.</p>
<p>These are only a few ways to use these helpers, this is really just the tip of the iceberg. The sky is the limit: create a select that lets users navigate through the pages, create a list of links (like flickr) that lets you navigate through pages, create a link that lets you order by any number of columns you want, etc. I know ruby has a bad rep when it comes to documentation, but I actually put some decent time into the <a href="http://searchlogic.rubyforge.org">Searchlogic documentation</a> and I think you will find it helpful. That&#8217;s your best resource for finding out everything <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a> has to offer.</p>
<div class="spacer5"></div>
<h2>Adding a search form</h2>
<p>&#8220;This is all great, but you said I could search my data&#8221;. Searching your data is just as easy. Just add this to the top of your index.html.erb</p>
<pre class="cobalt">
# app/views/users/index.html.erb
<span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> form_for <span class="Variable"><span class="Punctuation">@</span>search</span> <span class="Keyword">do </span><span class="Punctuation">|</span><span class="Variable">f</span><span class="Punctuation">|</span> <span class="Punctuation">%&gt;</span></span>
    <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">fieldset</span><span class="Punctuation">&gt;</span></span>
        <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">legend</span><span class="Punctuation">&gt;</span></span>Search Users<span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">legend</span><span class="Punctuation">&gt;</span></span>

        <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> f<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">fields_for</span></span> <span class="Variable"><span class="Punctuation">@</span>search</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">conditions</span></span> <span class="Keyword">do </span><span class="Punctuation">|</span><span class="Variable">users</span><span class="Punctuation">|</span> <span class="Punctuation">%&gt;</span></span>
            <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> users<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">label</span></span> <span class="Constant"><span class="Punctuation">:</span>first_name_keywords</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
            <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> users<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">text_field</span></span> <span class="Constant"><span class="Punctuation">:</span>first_name_keywords</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
            <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>

            <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> users<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">fields_for</span></span> users<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">object</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">orders</span></span> <span class="Keyword">do </span><span class="Punctuation">|</span><span class="Variable">orders</span><span class="Punctuation">|</span> <span class="Punctuation">%&gt;</span></span>
                <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> orders<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">label</span></span> <span class="Constant"><span class="Punctuation">:</span>total_gt</span><span class="Punctuation">,</span> <span class="String"><span class="Punctuation">&quot;</span>Has orders with a total greater than<span class="Punctuation">&quot;</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
                $<span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> orders<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">text_field</span></span> <span class="Constant"><span class="Punctuation">:</span>total_gt</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
            <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>

            <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> users<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">fields_for</span></span> users<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">object</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">user_group</span></span> <span class="Keyword">do </span><span class="Punctuation">|</span><span class="Variable">user_group</span><span class="Punctuation">|</span> <span class="Punctuation">%&gt;</span></span>
                <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user_group<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">label</span></span> <span class="Constant"><span class="Punctuation">:</span>name_starts_with</span><span class="Punctuation">,</span> <span class="String"><span class="Punctuation">&quot;</span>Belongs to user group with name that starts with<span class="Punctuation">&quot;</span></span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
                <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> user_group<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">text_field</span></span> <span class="Constant"><span class="Punctuation">:</span>name_starts_with</span> <span class="Punctuation">%&gt;</span></span><span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
                <span class="MetaTagA"><span class="Punctuation">&lt;</span><span class="MetaTagA">br</span> /<span class="Punctuation">&gt;</span></span>
            <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>
        <span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>
    <span class="MetaTagA"><span class="Punctuation">&lt;/</span><span class="MetaTagA">fieldset</span><span class="Punctuation">&gt;</span></span>
    <span class="EmbeddedSource"><span class="Punctuation">&lt;%=</span> f<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">submit</span></span> <span class="String"><span class="Punctuation">&quot;</span>Search<span class="Punctuation">&quot;</span></span> <span class="Punctuation">%&gt;</span></span>
<span class="EmbeddedSource"><span class="Punctuation">&lt;%</span> <span class="Keyword">end</span> <span class="Punctuation">%&gt;</span></span>
</pre>
<p>As I mentioned above <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a> creates default conditions on your columns based on the type. Letting you use a form builder to call those conditions. When it receives these conditions on the back-end it will do its &#8220;magic&#8221; and creates the proper SQL. Don&#8217;t worry about SQL injections, <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a> has you covered on that (see <a href="http://searchlogic.rubyforge.org">the documentation</a> for more info).</p>
<p>What&#8217;s great about this method of searching?</p>
<ol>
<li>Your search logic is in one place: the view.</li>
<li>You can add conditions by doing f.text_field &#8220;[column name]_[condition]&#8220;. So when your picky client calls up and says &#8220;Hey, we need a search field for finding emails that end with&#8230;&#8221; No prob: f.text_field :email_ends_with. Done!</li>
<li>You can traverse your relationships with fields_for and set conditions on related objects. Saweet!</li>
</ol>
<div class="spacer5"></div>
<h2>Ajaxified</h2>
<p>So you&#8217;re saying &#8220;this is great, but super old school, where&#8217;s the AJAX?!?!?&#8221; So you&#8217;re all about AJAX? No problem. In the example I have 3 examples: a <a href="http://searchlogic_example.binarylogic.com/non_ajax/users">non AJAX example</a>, an <a href="http://searchlogic_example.binarylogic.com/rails_ajax/users">AJAX example using the built in rails helpers</a>, and <a href="http://searchlogic_example.binarylogic.com/jquery/users">a jQuery AJAX example</a>. Check them out. You can <a href="https://github.com/binarylogic/searchlogic_example">view the source of the examples on github</a> (each example if named spaced into its own controller). On a side note, I highly recommend <a href="http://jquery.com/">jQuery</a>. I recently started using it and love it. I actually get excited to write javascript because I always find something new when digging through the documentation or plugins and unobtrusive javascript never felt so good.</p>
<div class="spacer5"></div>
<h2>Some helpful links</h2>
<p>This tutorial is really just the tip of the ice berg with <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a>. Checkout these links to see all it has to offer:</p>
<ul>
<li><a href="http://searchlogic_example.binarylogic.com">Live example based on this tutorial</a></li>
<li><a href="http://github.com/binarylogic/searchlogic_example">Source code for the live tutorial</a></li>
<li><a href="http://github.com/binarylogic/searchlogic">Searchlogic, the library that makes all of this magic happen</a></li>
<li><a href="http://searchlogic.rubyforge.org">Searchlogic documentation</a></li>
</ul>
<p>I am always interested in hearing feedback. Let me know what you think, what you like, what you don&#8217;t, that you hate the name, etc. I love criticism. <a href="http://github.com/binarylogic/searchlogic">Searchlogic</a> is under active development and I am always trying to improve it. I hope this tutorial was helpful to you and ultimately makes your life easier.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2008/09/07/tutorial-pagination-ordering-and-searching-with-searchlogic/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Searchlogic released!</title>
		<link>http://www.binarylogic.com/2008/09/01/searchlogic-released/</link>
		<comments>http://www.binarylogic.com/2008/09/01/searchlogic-released/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 21:56:00 +0000</pubDate>
		<dc:creator>benjohnson</dc:creator>
				<category><![CDATA[Searchlogic]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[searchgasm]]></category>
		<category><![CDATA[searching]]></category>

		<guid isPermaLink="false">0/2009/03/23/searchlogic-released</guid>
		<description><![CDATA[Searchlogic&#8217;s inspiration comes right from ActiveRecord. ActiveRecord lets you create objects that represent a record in the database, so why can&#8217;t you create objects that represent searching the database? Now you can! It&#8217;s searching, ordering, and pagination all in one.
            
Enough said, let me [...]]]></description>
			<content:encoded><![CDATA[<p><strong><a href="http://github.com/binarylogic/searchlogic/">Searchlogic&#8217;s</a> inspiration comes right from ActiveRecord. ActiveRecord lets you create objects that represent a record in the database, so why can&#8217;t you create objects that represent searching the database? Now you can! It&#8217;s searching, ordering, and pagination all in one.</strong></p>
<p>            <span id="more-12"></span></p>
<p>Enough said, let me show you some of my favorite features. If you are still interested you can just jump over to the <a href="http://github.com/binarylogic/searchlogic/">searchlogic github page</a> for a more detailed explanation.</p>
<p><strong>For the following examples lets assume these relationships: User =&gt; Orders =&gt; LineItems</strong></p>
<h2>Simple Searching Example</h2>
<pre class="cobalt">
<span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span><span class="Punctuation">(</span>
  <span class="Constant"><span class="Punctuation">:</span>conditions</span> <span class="Punctuation">=&gt;</span> <span class="Punctuation">{</span>
    <span class="Constant"><span class="Punctuation">:</span>first_name_contains</span> <span class="Punctuation">=&gt;</span> <span class="String"><span class="Punctuation">&quot;</span>Ben<span class="Punctuation">&quot;</span></span><span class="Punctuation">,</span>          <span class="Comment"><span class="Punctuation">#</span> first_name like '%Ben%'</span>
    <span class="Constant"><span class="Punctuation">:</span>email_ends_with</span> <span class="Punctuation">=&gt;</span> <span class="String"><span class="Punctuation">&quot;</span>binarylogic.com<span class="Punctuation">&quot;</span></span>   <span class="Comment"><span class="Punctuation">#</span> email like '%binarylogic.com'</span>
  <span class="Punctuation">}</span><span class="Punctuation">,</span>
  <span class="Constant"><span class="Punctuation">:</span>per_page</span> <span class="Punctuation">=&gt;</span> <span class="Constant">20</span><span class="Punctuation">,</span>                      <span class="Comment"><span class="Punctuation">#</span> limit 20</span>
  <span class="Constant"><span class="Punctuation">:</span>page</span> <span class="Punctuation">=&gt;</span> <span class="Constant">3</span><span class="Punctuation">,</span>                           <span class="Comment"><span class="Punctuation">#</span> offset 40, which starts us on page 3</span>
  <span class="Constant"><span class="Punctuation">:</span>order_as</span> <span class="Punctuation">=&gt;</span> <span class="String"><span class="Punctuation">&quot;</span>ASC<span class="Punctuation">&quot;</span></span><span class="Punctuation">,</span>
  <span class="Constant"><span class="Punctuation">:</span>order_by</span> <span class="Punctuation">=&gt;</span> <span class="Punctuation">{</span><span class="Constant"><span class="Punctuation">:</span>user_group</span> <span class="Punctuation">=&gt;</span> <span class="Constant"><span class="Punctuation">:</span>name</span><span class="Punctuation">}</span>   <span class="Comment"><span class="Punctuation">#</span> order user_groups.name ASC</span>
<span class="Punctuation">)</span>
</pre>
<p>same as above, but object based</p>
<pre class="cobalt">
search <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">new_search</span></span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">conditions</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">first_name_contains</span></span> <span class="Keyword">=</span> <span class="String"><span class="Punctuation">&quot;</span>Ben<span class="Punctuation">&quot;</span></span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">conditions</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">email_ends_with</span></span> <span class="Keyword">=</span> <span class="String"><span class="Punctuation">&quot;</span>binarylogic.com<span class="Punctuation">&quot;</span></span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">per_page</span></span> <span class="Keyword">=</span> <span class="Constant">20</span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">page</span></span> <span class="Keyword">=</span> <span class="Constant">3</span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">order_as</span></span> <span class="Keyword">=</span> <span class="String"><span class="Punctuation">&quot;</span>ASC<span class="Punctuation">&quot;</span></span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">order_by</span></span> <span class="Keyword">=</span> <span class="Punctuation">{</span><span class="Constant"><span class="Punctuation">:</span>user_group</span> <span class="Punctuation">=&gt;</span> <span class="Constant"><span class="Punctuation">:</span>name</span><span class="Punctuation">}</span>
search<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span>
</pre>
<p>In both examples, instead of using the &#8220;all&#8221; method you could use any search method: first, find(:all), find(:first), count, sum, average, etc, just like ActiveRecord.</p>
<h2>The beauty of searchlogic, integration with rails</h2>
<p>Using Searchlogic in rails is the best part, because rails has all kinds of nifty methods to make dealing with ActiveRecord objects quick and easy, especially with forms. So let’s take advantage of them! That’s the idea behind this plugin. Searchlogic is searching, ordering, and pagination all rolled into one simple plugin. Take all of that pagination and searching cruft out of your models and let Searchlogic handle it. Check it out: </p>
<pre class="cobalt">
<span class="Comment"><span class="Punctuation">#</span> app/controllers/users_controller.rb</span>
<span class="Keyword">def</span> <span class="Entity">index</span>
    <span class="Variable"><span class="Punctuation">@</span>search</span> <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">new_search</span></span><span class="Punctuation">(</span>params<span class="Punctuation">[</span><span class="Constant"><span class="Punctuation">:</span>search</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
    <span class="Variable"><span class="Punctuation">@</span>users</span><span class="Punctuation">,</span> <span class="Variable"><span class="Punctuation">@</span>users_count</span> <span class="Keyword">=</span> <span class="Variable"><span class="Punctuation">@</span>search</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">all</span></span><span class="Punctuation">,</span> <span class="Variable"><span class="Punctuation">@</span>search</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">count</span></span>
<span class="Keyword">end</span>
</pre>
<p>Now your view.</p>
<pre class="cobalt">
# app/views/users/index.html.haml
- form_for @search do |f|
 - f.fields_for @search.conditions do |users|
  = users.text_field :first_name_contains
  = users.calendar_date_select :created_after # nice rails plugin for replacing date_select
  - users.fields_for users.object.orders do |orders|
    = orders.select :total_gt, (1..100)
  = f.submit &quot;Search&quot;

- if @users_count &gt; 0
  %table
    %tr
      %th= order_by_link :account =&gt; :name
      %th= order_by_link :first_name
      %th= order_by_link :last_name
      %th= order_by_link :email
    - @users.each do |user|
      %tr
        %td= user.first_name
        %td= user.last_name
        %td= user.email

  Per page:
  = per_page_select
  Page:
  = page_select
- else
  No users returned
</pre>
<h3>Things to notice</h3>
<ol>
<li>Passing a search object right into form_for and fields_for</li>
<li>The built in conditions for each column and how you can traverse the relationships and set conditions on them</li>
<li>The order_by_link helper</li>
<li>The page_select and per_page_select helpers</li>
<li>All of your search logic is in 1 spot: your view. Nice and DRY.</li>
</ol>
<p><strong><a href="http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchlogic">See my tutorial on this example</a></strong></p>
<h2>Nifty methods for searching trees</h2>
<p>Just like the conditions you automatically get with each column. You automatically get conditions for searching tree data structures, if you&#8217;re model is a tree data structure.</p>
<pre class="cobalt">
<span class="Comment"><span class="Punctuation">#</span> User is a tree data structure.</span>
conditions <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">new_conditions</span></span>
conditions<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">child_of</span></span> <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">roots</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">first</span></span>                  <span class="Comment"><span class="Punctuation">#</span> Finds all children</span>
conditions<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">sibling_of</span></span> <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">first</span></span>                      <span class="Comment"><span class="Punctuation">#</span> Finds siblings</span>
conditions<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">descendant_of</span></span> <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">roots</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">first</span></span>             <span class="Comment"><span class="Punctuation">#</span> Finds all children, grandchildren, etc</span>
conditions<span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">inclusive_descendant_of</span></span> <span class="Keyword">=</span> <span class="Support">User</span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">roots</span></span><span class="FunctionCall"><span class="Punctuation">.</span><span class="Entity">first</span></span>   <span class="Comment"><span class="Punctuation">#</span> Includes root + children, grandchildren, etc.</span>
</pre>
<p>Any of these conditions can accept a User object or a User id.</p>
<h2>Get Started</h2>
<p>Check out the GitHub repository to get started:</p>
<p><strong><a href="http://github.com/binarylogic/searchlogic/">http://github.com/binarylogic/searchlogic/</a></strong></p>
<p>Or a tutorial I posted on using Searchlogic in rails:</p>
<p><strong><a href="http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchlogic">http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchlogic</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.binarylogic.com/2008/09/01/searchlogic-released/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>
