Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

311 lines (261 sloc) 10.803 kb
require 'rails_admin/config/proxyable'
require 'rails_admin/config/configurable'
require 'rails_admin/config/hideable'
require 'rails_admin/config/groupable'
module RailsAdmin
module Config
module Fields
class Base
include RailsAdmin::Config::Proxyable
include RailsAdmin::Config::Configurable
include RailsAdmin::Config::Hideable
include RailsAdmin::Config::Groupable
attr_reader :name, :properties, :abstract_model
attr_accessor :defined, :order, :section
attr_reader :parent, :root
def initialize(parent, name, properties)
@parent = parent
@root = parent.root
@abstract_model = parent.abstract_model
@defined = false
@name = name.to_sym
@order = 0
@properties = properties
@section = parent
end
register_instance_option :css_class do
"#{self.name}_field"
end
def type_css_class
"#{type}_type"
end
def virtual?
properties.blank?
end
register_instance_option :column_width do
nil
end
register_instance_option :sortable do
!virtual? || children_fields.first || false
end
register_instance_option :searchable do
!virtual? || children_fields.first || false
end
register_instance_option :queryable? do
!virtual?
end
register_instance_option :filterable? do
!!searchable
end
register_instance_option :search_operator do
@search_operator ||= RailsAdmin::Config.default_search_operator
end
# serials and dates are reversed in list, which is more natural (last modified items first).
register_instance_option :sort_reverse? do
false
end
# list of columns I should search for that field [{ :column => 'table_name.column', :type => field.type }, {..}]
register_instance_option :searchable_columns do
@searchable_columns ||= case self.searchable
when true
[{ :column => "#{self.abstract_model.table_name}.#{self.name}", :type => self.type }]
when false
[]
when :all # valid only for associations
table_name = self.associated_model_config.abstract_model.table_name
self.associated_model_config.list.fields.map { |f| { :column => "#{table_name}.#{f.name}", :type => f.type } }
else
[self.searchable].flatten.map do |f|
if f.is_a?(String) && f.include?('.') # table_name.column
table_name, column = f.split '.'
type = nil
elsif f.is_a?(Hash) # <Model|table_name> => <attribute|column>
am = f.keys.first.is_a?(Class) && AbstractModel.new(f.keys.first)
table_name = am && am.table_name || f.keys.first
column = f.values.first
property = am && am.properties.find{ |p| p[:name] == f.values.first.to_sym }
type = property && property[:type]
else # <attribute|column>
am = (self.association? ? self.associated_model_config.abstract_model : self.abstract_model)
table_name = am.table_name
column = f
property = am.properties.find{ |p| p[:name] == f.to_sym }
type = property && property[:type]
end
{ :column => "#{table_name}.#{column}", :type => (type || :string) }
end
end
end
register_instance_option :formatted_value do
value.to_s
end
# output for pretty printing (show, list)
register_instance_option :pretty_value do
formatted_value.presence || ' - '
end
# output for printing in export view (developers beware: no bindings[:view] and no data!)
register_instance_option :export_value do
pretty_value
end
# Accessor for field's help text displayed below input field.
register_instance_option :help do
(@help ||= {})[::I18n.locale] ||= (required? ? I18n.translate("admin.form.required") : I18n.translate("admin.form.optional")) + '. '
end
register_instance_option :html_attributes do
{}
end
register_instance_option :default_value do
nil
end
# Accessor for field's label.
#
# @see RailsAdmin::AbstractModel.properties
register_instance_option :label do
(@label ||= {})[::I18n.locale] ||= abstract_model.model.human_attribute_name name
end
register_instance_option :hint do
(@hint ||= "")
end
# Accessor for field's maximum length per database.
#
# @see RailsAdmin::AbstractModel.properties
register_instance_option :length do
@length ||= properties && properties[:length]
end
# Accessor for field's length restrictions per validations
#
register_instance_option :valid_length do
@valid_length ||= abstract_model.model.validators_on(name).find{|v|
v.kind == :length }.try{|v| v.options} || {}
end
register_instance_option :partial do
:form_field
end
# Accessor for whether this is field is mandatory.
#
# @see RailsAdmin::AbstractModel.properties
register_instance_option :required? do
context = (bindings && bindings[:object] ? (bindings[:object].persisted? ? :update : :create) : :nil)
(@required ||= {})[context] ||= !!([name] + children_fields).uniq.find do |column_name|
!!abstract_model.model.validators_on(column_name).find do |v|
!v.options[:allow_nil] and
[:presence, :numericality, :attachment_presence].include?(v.kind) and
(v.options[:on] == context or v.options[:on].blank?)
end
end
end
# Accessor for whether this is a serial field (aka. primary key, identifier).
#
# @see RailsAdmin::AbstractModel.properties
register_instance_option :serial? do
properties && properties[:serial?]
end
register_instance_option :view_helper do
:text_field
end
register_instance_option :read_only? do
not editable?
end
# init status in the view
register_instance_option :active? do
false
end
register_instance_option :visible? do
returned = true
(RailsAdmin.config.default_hidden_fields || {}).each do |section, fields|
if self.section.is_a?("RailsAdmin::Config::Sections::#{section.to_s.camelize}".constantize)
returned = false if fields.include?(self.name)
end
end
returned
end
# columns mapped (belongs_to, paperclip, etc.). First one is used for searching/sorting by default
register_instance_option :children_fields do
[]
end
register_instance_option :render do
bindings[:view].render :partial => "rails_admin/main/#{partial}", :locals => {:field => self, :form => bindings[:form] }
end
def editable?
return false if @properties && @properties[:read_only]
active_model_attr_accessible = !bindings[:object].class.active_authorizer[bindings[:view].controller.send(:_attr_accessible_role)].deny?(self.method_name)
return true if active_model_attr_accessible
if RailsAdmin::Config.yell_for_non_accessible_fields
Rails.logger.debug "\n\n[RailsAdmin] Please add 'attr_accessible :#{self.method_name}' in your '#{bindings[:object].class}' model definition if you want to make it editable.\nYou can also explicitely mark this field as read-only: \n\nconfig.model #{bindings[:object].class} do\n field :#{self.name} do\n read_only true\n end\nend\n\nAdd 'config.yell_for_non_accessible_fields = false' in your 'rails_admin.rb' initializer if you do not want to see these warnings\n\n"
end
false
end
# Is this an association
def association?
kind_of?(RailsAdmin::Config::Fields::Association)
end
# Reader for validation errors of the bound object
def errors
([name] + children_fields).uniq.map do |column_name|
bindings[:object].errors[column_name]
end.uniq.flatten
end
# Reader whether field is optional.
#
# @see RailsAdmin::Config::Fields::Base.register_instance_option(:required?)
def optional?
not required?
end
# Inverse accessor whether this field is required.
#
# @see RailsAdmin::Config::Fields::Base.register_instance_option(:required?)
def optional(state = nil, &block)
if !state.nil? || block
required state.nil? ? proc { false == (instance_eval &block) } : false == state
else
optional?
end
end
# Writer to make field optional.
#
# @see RailsAdmin::Config::Fields::Base.optional
def optional=(state)
optional(state)
end
# Reader for field's type
def type
@type ||= self.class.name.to_s.demodulize.underscore.to_sym
end
# Reader for field's value
def value
bindings[:object].safe_send(name)
end
# Reader for nested attributes
register_instance_option :nested_form do
false
end
def inverse_of
nil
end
def method_name
name
end
def html_default_value
bindings[:object].new_record? && self.value.nil? && !self.default_value.nil? ? self.default_value : nil
end
def inspect
"#<#{self.class.name}[#{name}] #{
instance_variables.map do |v|
value = instance_variable_get(v)
if [:@parent, :@root, :@section, :@children_fields_registered,
:@associated_model_config, :@group, :@bindings].include? v
if value.respond_to? :name
"#{v}=#{value.name.inspect}"
else
"#{v}=#{value.class.name}"
end
else
"#{v}=#{value.inspect}"
end
end.join(", ")
}>"
end
end
end
end
end
Jump to Line
Something went wrong with that request. Please try again.