Class: Edgar::SearchForm

Inherits:
Search
  • Object
show all
Defined in:
app/models/edgar/search_form.rb

Overview

'SearchForm' instance contains search-conditions entered at search-form as:

  1. search conditions (mainly string, but integers for timestamp) for eash attribute of model

  2. operator (=, <, >, ...) for each attribute

  3. parent name for redraw

Model(ActiveRecord) intance itself (e.g. Customer.new) doesn't satisfy to keep search condition because:

  1. id cannot be set because of protection.

  2. search condition may have operator (like '=', '>=')

This is why SearchForm class is created.

NOTE: model is stored in SearhForm as model_str.constantize to avoid following error:

ArgumentError (undefined class/module Customer)

Operator

Operator for some search-fields (e.g. integer, date) are initialized by params. For example, when search condition for Question screen GUI is:

Priority < 3

then, params is:

:priority=>3, :search_form_operator=>{:priority=>'<'}

and SearchForm object is built as:

s = SearchForm.new(Question, params[:search])

and finally it generates SQL condition as follows:

s.conditions      # ["priority<?", 3]

Parent name

In order to hold parent object 'name' value for redraw, _parent[] hash is used. It is passed from params.

BUGS

date-type(e.g. 'created_at(1i)'=2010, 'created_at(2i)'=2, ...) and datetime-type are not supported now while jQuery datepicker is OK.

Defined Under Namespace

Classes: Operator

Instance Attribute Summary (collapse)

Attributes inherited from Search

#_klass_str, #errors

Instance Method Summary (collapse)

Methods inherited from Search

#column_type, #persisted?

Constructor Details

- (SearchForm) initialize(klass, attrs = {})

Build SearchForm object from 'klass' which is a ActiveRecord class, and attrs.

INPUTS

klass

ActiveRecord

attrs

hash of key=>value pair



99
100
101
102
103
104
105
# File 'app/models/edgar/search_form.rb', line 99

def initialize(klass, attrs={})
  super(klass)
  @_table_name  = klass.table_name
  @attrs        = attrs.dup
  @_operator    = Operator.new(attrs[:edgar_search_form_operator])
  @_parent      = attrs[:search_form_parent]
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

- (Object) method_missing(method_name, *args)

map attribute name to hash entry. This mechanism is required to be used in 'form_for' helper.

When column type is integer and has digits value, return integer. This is required for selection helper. Even it is integer but has no value, keeps blank.

When attribute name ends '=', assignment to hash works.

EXAMPLE

s = Searchform.new(Product, :name=>'a') s.name s.conditions # ["name=?", "a"] s.name = 'b' # method_missing('name=', 'b') is called s.conditions # ["name=?", "b"]



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'app/models/edgar/search_form.rb', line 123

def method_missing(method_name, *args)
  if method_name.to_s =~ /^(.*)=$/
    @attrs[$1.to_sym] = args[0]
  else
    val = @attrs[method_name.to_sym]
    case column_type(method_name)
    when :integer
      if val =~ /^\d+$/
        val.to_i
      else
        val
      end
    else
      val
    end
  end
end

Instance Attribute Details

- (Object) _operator

Returns the value of attribute _operator



47
48
49
# File 'app/models/edgar/search_form.rb', line 47

def _operator
  @_operator
end

- (Object) _parent

Returns the value of attribute _parent



47
48
49
# File 'app/models/edgar/search_form.rb', line 47

def _parent
  @_parent
end

Instance Method Details

- (Object) col_name(col) (private)

generate full-qualified column name. Example: authors.name



204
205
206
# File 'app/models/edgar/search_form.rb', line 204

def col_name(col)
  [@_table_name, col.name].join('.')
end

- (Object) conditions

Generate search-conditions. Wildcard search by '*' is supported on string attribute.

RETURN

condition_string, value_array

values for :conditions option on model



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'app/models/edgar/search_form.rb', line 146

def conditions
  return ['1=0'] if !valid?

  conds       = []
  values      = []
  for col in @_klass_str.constantize.columns do
    col_str = col_name(col)
    val     = @attrs[encode_name(col)]
    if !val.blank?
      case col.type
      when :string, :text
        if val =~ /\*$/
          conds   << col_str + ' like ?'
          values  << val.gsub(/\*$/, '%')
        else
          conds   << col_str + '=?'
          values  << val
        end
      when :datetime
        conds   << sprintf("date(timezone('%s',%s))",
                        Edgar::BaseConfig::DEFAULT_TIMEZONE_FOR_TIMESTAMP_DATE_COMPARISON,
                        col_str) +
                   @_operator.exp(encode_name(col))
        values  << val.to_s
      else
        conds   << col_str + @_operator.exp(encode_name(col))
        values  << val
      end
    end
  end
  return [conds.join(' and ')] + values
end

- (Object) decode_name(col) (private)

SEE ALSO

encode_name()



200
201
# File 'app/models/edgar/search_form.rb', line 200

def decode_name(col)
end

- (Object) encode_name(col) (private)

'rec.id' is unintentionally interpreted as Object.id rather than rec.attrs so encode it to _id.

'rec.type' has the same issue so to _type.

SEE ALSO

decode_name()



187
188
189
190
191
192
193
194
195
# File 'app/models/edgar/search_form.rb', line 187

def encode_name(col)
  if col.name == 'id'
    :_id
  elsif col.name == 'type'
    :_type
  else
    col.name.to_sym
  end
end

- (Object) validate_data_type (private)



208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'app/models/edgar/search_form.rb', line 208

def validate_data_type
  for col in @_klass_str.constantize.columns do
    col_str     = col_name(col)
    encoded_col = encode_name(col)
    val     = @attrs[encoded_col]
    case col.type
    when :integer
      if val.present? && val !~ /^[\d\.\-]+$/
        errors.add(encoded_col, :not_an_integer)
      end
    else
    end
  end
end