Skip to content

Instantly share code, notes, and snippets.

@ligfx
Created February 15, 2012 03:58
Show Gist options
  • Save ligfx/1833073 to your computer and use it in GitHub Desktop.
Save ligfx/1833073 to your computer and use it in GitHub Desktop.
Espresso
<% filter.opts.each do |(k, v)| %>
<input type="hidden" name="<%= k %>" value="<%= v %>" />
<% end %>
<select name="<%= filter.name %>">
<option value="">-- Pick an issue</option>
<% filter.collection.each do |item| %>
<option value="<%= item.value %>"
<% if params[filter.name] == item.value.to_s %>
selected="selected"
<% end %>
>
<%= item.name %>
</option>
<% end %>
</select>
require 'ostruct'
class ArticleAdmin
def columns
[
OpenStruct.new(value: :title.to_proc, name: "Title", link?: true, sort: :title),
OpenStruct.new(value: :created_at.to_proc, name: "Created At", sort: :created_at),
OpenStruct.new(value: ->(article) { article.issue.try(:name) }, name: "Issue", sort: :issue_id)
]
end
end
class ArticleFilter < ModelFilter
self.model = Article
self.filter_classes = [
BelongsToFilter.factory(:model_name => :issue, :pretty_attribute => :name)
]
end
class ArticlesController < ApplicationController
respond_to :html
def index
@model = ArticleAdmin.new
@filter = ArticleFilter.new(params)
@articles = @filter.collection.page(params[:page]).per(10)
respond_with @articles
end
end
class BelongsToFilter
class_attribute :model_name, :pretty_attribute
def self.factory(opts={})
Class.new(self).tap do |k|
k.model_name = opts[:model_name]
k.pretty_attribute = opts[:pretty_attribute]
end
end
attr_accessor :opts
def initialize(params)
self.opts = {}
self.opts[model_name] = params[model_name]
end
def call(query)
query.where("#{model_name.to_s}_id" => self.opts[model_name]) if self.opts[model_name].present?
end
def type
"select"
end
def name
model_name
end
def collection
model_name.to_s.camelize.constantize.all.map do |i|
OpenStruct.new(
:item =>i,
:value => i.id,
:name => i.send(pretty_attribute)
)
end
end
end
<div id="topbar">
<h1>Workflow</h1>
</div>
<div id="container">
<div id="main">
<div id="main_inner">
<h1>Articles</h1>
<table class="table table-striped table-condensed">
<thead>
<tr>
<% @model.columns.each do |col| %>
<th><%= col.name %></th>
<% end %>
</tr>
</thead>
<% @articles.each do |article| %>
<tr>
<% @model.columns.each do |col| %>
<td>
<% if col.link? %><a href="<%= url_for article %>"><% end %>
<%= col.value.call(article) %>
<% if col.link? %></a><% end %>
</td>
<% end %>
</tr>
<% end %>
</table>
<%= paginate @articles %>
</div>
</div>
<div id="left">
<div id="left_inner">
<h1>Navigation</h1>
</div>
</div>
<div id="right">
<div id="right_inner">
<h1>Filter</h1>
<%= request.query_parameters %>
<h2>Issue</h2>
<form>
<% @filter.filters.each do |filter| %>
<%= render :partial => filter.type, :locals => { :filter => filter } %>
<% end %>
<input type="hidden" name="sort" value="<%= params[:sort] %>" />
<input type="submit" />
</form>
<h2>Sort</h2>
<% @model.columns.each do |col| %>
<p>
<%= col.name %>:
<%= link_to "Asc", @filter.sort("#{col.sort}:asc") %> |
<%= link_to "Desc", @filter.sort("#{col.sort}:desc") %>
</p>
<% end %>
</div>
</div>
</div>
class ModelFilter
class_attribute :model, :filter_classes
attr_accessor :collection, :filters
def initialize(params, initial_collection=Article.scoped)
@filters = filter_classes.map { |k| k.new(params) }
@filters.push SortFilter.new params
@collection = @filters.inject(initial_collection) do |c, f|
f.call(c) || c
end
end
def sort(param)
@filters.map(&:opts).inject(&:merge).merge(:sort => param)
end
end
class SortFilter
attr_accessor :opts
def initialize(params)
self.opts = {}
self.opts[:sort] = if params[:sort].present?
params[:sort].gsub(":", " ")
end
end
def type; "hidden"; end
def call(query)
query.order(opts[:sort]) if opts[:sort]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment