module RearSetup

Public Instance Methods

assoc_columns(*columns) click to toggle source

when rendering some model in a “remote” association pane, all columns of current model will be displayed.

‘assoc_columns` allow to set a list of “remotely” displayed columns.

# File lib/rear/setup/associations.rb, line 28
def assoc_columns *columns
  @__rear__assoc_columns = columns if columns.any?
  @__rear__assoc_columns
end
decorative_filter(*args, &proc) click to toggle source

sometimes you need to filter by some value that has too much options. For ex. you want to filter pages by author and there are about 1000 authors in db. displaying all authors within a single dropdown filter is kinda cumbersome. we need to somehow narrow them down. decorative filters allow to do this with easy. in our case, we do not display the authors until a letter selected.

@example

class Pages < E
  include Rear
  model PageModel

  decorative_filter :letter, :select do
    ('A'..'Z').to_a
  end

  filter :author_id, :select do
    if letter = filter?(:letter) # use here the name of decorative filter
      authors = {}
      AuthorModel.all(:name.like => "%#{letter}%").each |a|
        authors[a.id] = a.name
      end
      authors
    else
      {"" => "Select a letter please"}
    end
  end
end

@note

decorative filters will not actually query the db, so you can name them as you want.

@note

decorative filters does not support custom comparison functions
# File lib/rear/setup/filters.rb, line 200
def decorative_filter *args, &proc
  html_attrs = args.last.is_a?(Hash) ? Hash[args.pop] : {}
  setup = {decorative?: true, cmp: FILTERS__DECORATIVE_CMP}
  filter *args << html_attrs.merge(setup), &proc
end
editor_attrs(attrs = {}) click to toggle source

set HTML attributes to be used on all columns only on editor pages. @note will override any attrs set via ‘html_attrs`

# File lib/rear/setup/columns.rb, line 105
def editor_attrs attrs = {}
  @__rear__editor_attrs = attrs if attrs.any? && @__rear__editor_attrs.nil?
  @__rear__editor_attrs || html_attrs
end
filter(column, type = nil, opts_and_or_html_attrs = {}) click to toggle source

add a filter.

by default a text filter will be rendered. to define filters of another type, pass desired type as a Symbol via second argument.

acceptable types:

- :string/:text
- :select
- :radio
- :checkbox
- :date
- :datetime
- :time
- :boolean

@note comparison function

:text/:string filters will use :like comparison function by default:
... WHERE name LIKE '%VALUE%' ...

:checkbox filters will use :in comparison function by default:
... WHERE column IN ('VALUE1', 'VALUE2') ...
if you use a custom cmp function with a :checkbox filter,
filter's column will be compared to each selected value:
... WHERE (column LIKE '%VALUE1%' OR column LIKE '%VALUE2%') ...

any other types will use :eql comparison function by default:
"... WHERE created_at = 'VALUE' ...

to use a non-default comparison function, set it via :cmp option:
`filter :name, :cmp => :eql`

available comparison functions:
  - :eql       # equal
  - :not       # not equal
  - :gt        # greater than
  - :gte       # greater than or equal
  - :lt        # less than
  - :lte       # less than or equal
  - :like      # - column LIKE '%VALUE%'
  - :unlike    # - column NOT LIKE '%VALUE%'
  - :_like     # match beginning of line - column LIKE 'VALUE%'
  - :_unlike   # - column NOT LIKE 'VALUE%'
  - :like_     # match end of line - column LIKE '%VALUE'
  - :unlike_   # - column NOT LIKE '%VALUE'
  - :_like_    # exact match - column LIKE 'VALUE'
  - :_unlike_  # - column NOT LIKE 'VALUE'

@note if type not given,

Rear will use the type of the column with same name, if any.
if no column found, it will use :text

@note :radio, :checkbox and :select filters requires a block to run.

block should return an Array or a Hash.
use an Array when stored keys are the same as displayed values.
use a  Hash  when stored keys are different.
Important! if no block given, Rear will search for a column
with same name and type and inherit options from there.
so if you have say a :checkbox column named :colors with defined options,
you only need to do `filter :colors`, without specifying type and options.
type and options will be inherited from earlier defined column.

@example

class Page < ActiveRecord::Base
  # ...
  include Rear
  rear do

    # text filter using :like comparison function
    filter :name

    # text filter using :eql comparison function
    filter :name, :cmp => :eql

    # date filter using :eql comparison function
    filter :created_at, :date

    # date filter using :gte comparison function
    filter :created_at, :date, :cmp => :gte

    # dropdown filter using :eql comparison function
    filter :color, :select do
      ['Red', 'Green', 'Blue']
    end

    # dropdown filter using :like comparison function
    filter :color, :select, :cmp => :like do
      ['Red', 'Green', 'Blue']
    end
  end
end

@example :radio filter using Hash

rear do
  filter :color, :radio do
    {'r' => 'Red', 'g' => 'Green', 'b' => 'Blue'}
  end
end

@example inheriting type and options from a earlier defined column

rear do
  column :colors, :checkbox do
    options 'Red', 'Green', 'Blue'
  end

  filter :colors # type and options inherited from :colors column
end

@param [Symbol] column @param [Symbol] type @param [Hash] opts_and_or_html_attrs @options opts_and_or_html_attrs :cmp comparison function @options opts_and_or_html_attrs :label @param [Proc] options block used on :select, :radio and :checkbox filters

should return Array or Hash.
# File lib/rear/setup/filters.rb, line 121
def filter column, type = nil, opts_and_or_html_attrs = {}, &proc
  
  opts = (opts_and_or_html_attrs||{}).dup
  type.is_a?(Hash) && (opts = type.dup) && (type = nil) && (opts_and_or_html_attrs = nil)
  matching_column = columns.find {|c| c && c.first == column}
  
  # if no type given, inheriting it from a column with same name, if any.
  type ||= (matching_column||[])[1]
  type = FILTERS__DEFAULT_TYPE unless FILTERS__HANDLED_TYPES.include?(type)

  # if filter is of :select, :radio or :checkbox type and no options block given,
  # inheriting it from a column with same name, if any.
  if proc.nil? && matching_column && matching_column[1] == type
    mci = RearInput.new(matching_column[0], type, &matching_column[3])
    mci.optioned? && proc = lambda { mci.options }
  end

  # using defaults if no comparison function given
  unless cmp = opts.delete(:cmp)
    cmp = case type
    when :text, :string
      :like
    when :checkbox
      :in
    else
      :eql
    end
  end

  unless label = opts.delete(:label)
    label = column.to_s
    label << '?' if type == :boolean
  end

  (filters[column.to_sym] ||= {})[cmp] = {
       template: 'filters/%s.slim' % type,
           type: type,
          label: label.freeze,
    decorative?: opts.delete(:decorative?),
          attrs: opts.freeze,
           proc: proc
  }.freeze
end
html_attrs(attrs = {}) click to toggle source

set HTML attributes to be used on all columns on both pane and editor pages

# File lib/rear/setup/columns.rb, line 91
def html_attrs attrs = {}
  @__rear__html_attrs = attrs if attrs.any? && @__rear__html_attrs.nil?
  @__rear__html_attrs || {}
end
ignore_assoc(*assocs)
Alias for: ignored_assocs
ignore_assocs(*assocs)
Alias for: ignored_assocs
ignored_assoc(*assocs)
Alias for: ignored_assocs
ignored_assocs(*assocs) click to toggle source

ignore some assocs. this is a cosmetic measure - assocs just wont be displayed on frontend but the API for their manipulation will still work

# File lib/rear/setup/associations.rb, line 15
def ignored_assocs *assocs
  (@__rear__ignored_assocs ||= []).concat(assocs) if assocs.any?
  (@__rear__ignored_assocs ||  [])
end
input(name, type = nil, opts_and_or_html_attrs = {}) click to toggle source

add new column or override automatically added one

@param [Symbol] name @param [Symbol] type one of [:string, :text, :date, :time, :datetime, :boolean]

default: :string

@param [Hash] opts_and_or_html_attrs @option opts_and_or_html_attrs :pane

when set to false the column wont be displayed on pane pages

@option opts_and_or_html_attrs :editor

when set to false the column wont be displayed on editor pages

@option opts_and_or_html_attrs :label @option opts_and_or_html_attrs :readonly @option opts_and_or_html_attrs :disabled @option opts_and_or_html_attrs :multiple @option opts_and_or_html_attrs any attributes to be added to HTML tag

@example

input :name
# => <input type="text" value="...">

@example

input :name, :style => "width: 100%;"
# => <input style="width: 100%;" type="text" ...>

@example

input :name, :text, :cols => 40
# => <textarea cols="40" ...>...</textarea>

@example display author name only on pane pages

input(:author_id) { disable :editor }

@example Ace Editor

input :content, :ace

@example CKEditor

input :content, :ckeditor
# File lib/rear/setup/columns.rb, line 40
def input name, type = nil, opts_and_or_html_attrs = {}, &proc

  type.is_a?(Hash) && (opts_and_or_html_attrs = type) && (type = nil)
  opts_and_or_html_attrs[:row] = opts_and_or_html_attrs[:row] ?
    opts_and_or_html_attrs[:row].to_s : @__rear__row

  existing_column = nil
  columns.each_with_index {|c,i| c && c.first == name && existing_column = [c,i]}
  column = existing_column ? Array.new(existing_column.first) : []

  column[0] = name
  column[1] = type ? type.to_s.downcase.to_sym : column[1] || COLUMNS__DEFAULT_TYPE
  column[2] = (column[2]||{}).merge(opts_and_or_html_attrs).freeze
  column[3] = proc
  column.freeze

  existing_column ?
    columns[existing_column.last] = column :
    columns << column
end
internal_filter(&proc) click to toggle source
# then we using internal_filter
# to yield selected category and filter articles
internal_filter do
  if category_id = filter?(:Category)
    Article.all(category_id: category_id.to_i)
  end
end

end

# File lib/rear/setup/filters.rb, line 304
def internal_filter &proc
  # instance_exec at runtime is expensive enough,
  # so compiling procs into methods at load time.
  chunks = [self.to_s, proc.__id__]
  name = ('__rear__%s__' % chunks.join('_').gsub(/\W/, '_')).to_sym
  define_method name, &proc
  private name
  internal_filters.push(name)
end
ipp(n = nil)
Alias for: items_per_page
items_per_page(n = nil) click to toggle source
# File lib/rear/setup/generic.rb, line 33
def items_per_page n = nil
  @__rear__ipp = n.to_i if n
  @__rear__ipp || 10
end
Also aliased as: ipp
label(label = nil)
Alias for: menu_label
menu_group(group = nil) click to toggle source

put current controller under some group.

@example put Articles and Pages under Cms dropdown

class Articles < E
  include Rear
  under :Cms
end
class Pages < E
  include Rear
  under :Cms
end
Also aliased as: under
menu_label(label = nil) click to toggle source

by default all controllers are shown in main menu using the demodulized controller name.

to use a custom label, set it via ‘menu_label` or its alias - `label` to hide a controller from menu set label to false.

Also aliased as: label
menu_position(position = nil) click to toggle source

by default controllers will be shown in the menu in the order they was defined. to have a controller shown before other ones set its menu_position to a higher number.

Also aliased as: position
model(model = nil, opts = {}) click to toggle source

tell controller to create a CRUD interface for given model opts and proc will be passed to Espresso’s ‘crudify` helper.

@param [Class] model @param [Hash] opts to be passed to ‘crudify` method @param [Proc] proc to be passed to `crudify` method

# File lib/rear/setup/generic.rb, line 10
def model model = nil, opts = {}, &proc
  return @__rear__model if @__rear__model || model.nil?
  model = RearUtils.extract_constant(model)
  RearUtils.is_orm?(model) ||
    raise(ArgumentError, '"%s" is not a ActiveRecord/DataMapper/Sequel model' % model.inspect)
  @__rear__model = model
  @__rear__default_label = model.name.gsub(/\W/, '_').freeze
  RearControllerSetup.crudify self, model, opts, &proc
end
on_delete(&proc) click to toggle source
# File lib/rear/setup/generic.rb, line 50
def on_delete &proc
  before :destroy, &proc
end
Also aliased as: on_destroy
on_destroy(&proc)
Alias for: on_delete
on_save(&proc) click to toggle source

executed when new item created and when existing item updated

# File lib/rear/setup/generic.rb, line 40
def on_save &proc
  # const_get(:RearController).
  before :save, &proc
end
on_update(&proc) click to toggle source

executed when existing item updated

# File lib/rear/setup/generic.rb, line 46
def on_update &proc
  before :update, &proc
end
order_by(*columns) click to toggle source
# File lib/rear/setup/generic.rb, line 28
def order_by *columns
  @__rear__order = columns if columns.any?
  @__rear__order
end
pane_attrs(attrs = {}) click to toggle source

set HTML attributes to be used on all columns only on pane pages. @note will override any attrs set via ‘html_attrs`

# File lib/rear/setup/columns.rb, line 98
def pane_attrs attrs = {}
  @__rear__pane_attrs = attrs if attrs.any? && @__rear__pane_attrs.nil?
  @__rear__pane_attrs || html_attrs
end
pkey(key = nil) click to toggle source
# File lib/rear/setup/generic.rb, line 20
def pkey key = nil
  return unless model
  @__rear__pkey = key if key
  @__rear__pkey ||
    raise(ArgumentError, "Was unable to automatically detect primary key for %s model.
      Please set it manually via `pkey key_name`" % model)
end
position(position = nil)
Alias for: menu_position
quick_filter(column, *args) click to toggle source

@example Array with default comparison function

quick_filter :color, 'Red', 'Green', 'Blue'
... WHERE color = '[Red|Green|Blue]'

@example Array with custom comparison function

quick_filter :color, 'Red', 'Green', 'Blue', :cmp => :like
... WHERE color LIKE '[Red|Green|Blue]'

@example Hash with default comparison function

quick_filter :color, 'r' => 'Red', 'g' => 'Green', 'b' => 'Blue'
... WHERE color = '[r|g|b]'

@example Hash with custom comparison function

quick_filter :color, :cmp => :like, 'r' => 'Red', 'g' => 'Green', 'b' => 'Blue'
... WHERE color LIKE '%[r|g|b]%'

@example Hash with comparison function defined per filter

quick_filter :color, [:like, 'r'] => 'Red', 'g' => 'Green', 'b' => 'Blue'
on Red
... WHERE color LIKE '%r%'
on Green or Blue
... WHERE color = '[g|b]'
# File lib/rear/setup/filters.rb, line 229
def quick_filter column, *args
  
  options = args.last.is_a?(Hash) ? args.pop : {}
  cmp = options.delete(:cmp) || :eql
  query_formats = FILTERS__QUERY_MAP.call(orm)
  if query_format = query_formats[cmp]
    options = Hash[options.map do |k,v|
      [
        v.to_s,
        k.is_a?(Array) ? [query_formats[k.first], k.last] : [query_format, k]
      ]
    end]

    # if options provided as arguments, adding them to options Hash
    args.each {|a| options[a.to_s] = [query_format, a.to_s] }

    # if no options given,
    # inheriting them from a column with same name, if any.
    if options.empty? && mc = columns.find {|c| c && c.first == column}
      mci = RearInput.new(mc[0], mc[1], &mc[3])
      mci.optioned? && mci.options.each_pair do |k,v|
        options[v.to_s] = [query_format, k]
      end
    end

    quick_filters[column.to_sym] = options
  end
end
readonly!() click to toggle source
# File lib/rear/setup/generic.rb, line 55
def readonly!
  @__rear__readonly = true
end
readonly_assoc(*assocs)
Alias for: readonly_assocs
readonly_assocs(*assocs) click to toggle source

make some assocs readonly. this is a cosmetic measure - frontend just wont let user modify them but the API for their manipulation will still work

# File lib/rear/setup/associations.rb, line 6
def readonly_assocs *assocs
  (@__rear__readonly_assocs ||= []).concat(assocs) if assocs.any?
  (@__rear__readonly_assocs ||  [])
end
Also aliased as: readonly_assoc
reset_columns!() click to toggle source

reset any automatically(or manually) added columns

# File lib/rear/setup/columns.rb, line 62
def reset_columns!
  @__rear__columns = {}
end
row(label = nil, &proc) click to toggle source

display multiple columns in a row(on editor)

@example using a block

row :Location do
  column :country
  column :state
  column :city
end

@example without a block

column :country, :row => :Location
column :state,   :row => :Location
column :city,    :row => :Location
# File lib/rear/setup/columns.rb, line 82
def row label = nil, &proc
  # explicit labels will be strings and implicit ones will be numbers
  # as a way to distinguish them when rendering templates
  @__rear__row = label ? label.to_s : (Time.now.to_f + rand)
  self.instance_exec(&proc) if proc
  @__rear__row = nil
end
under(group = nil)
Alias for: menu_group