Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Classified < ActiveRecord::Base
- DataFieldsFilePath = "test/fixtures/staticdata/type_of_goods_datafields.yml"
- acts_as_mappable
- acts_as_simply_searchable :fields_mapping => {
- "administrative_area_code" => "address.administrative_area_code",
- "area" => "address.area",
- "area_size_from" => "area_size_from",
- "area_size_to" => "area_size_to",
- "bedrooms" => "number_of_bedrooms",
- "bedrooms_from" => "number_of_bedrooms_from",
- "city" => "address.city",
- "description" => "description",
- "is_published" => "is_published",
- "is_sold" => "is_sold",
- "office_id" => "office_id",
- "postal_code" => "address.postal_code",
- "postal_code_in" => "address.postal_code_in",
- "price_from" => "price_from",
- "price_to" => "price_to",
- "ref" => "ref",
- "rooms" => "number_of_rooms",
- "rooms_from" => "number_of_rooms_from",
- "sort_by" => "sort_by",
- "sort_order" => "sort_order",
- "tags" => "tags.name",
- "title" => "title",
- "type" => "type",
- "transaction" => "type_of_transaction",
- "user_id" => "user_id"
- },
- :find_method => 'paginate',
- :pagination_options => {:per_page => 10}
- #internationalization
- self.keep_translations_in_model = true
- translates :title, :description, :base_as_default => true, :multiple_base_language => true
- #relationships
- belongs_to :user
- belongs_to :office
- belongs_to :program
- #belongs_to :type, :class_name => "TypeOfGood", :foreign_key => "name"
- #belongs_to :type_of_transaction, :class_name => "TypeOfTransaction", :foreign_key => "name"
- has_one :address, :as => :addressable, :dependent => :destroy
- has_many :attachments, :as => :assetable, :order => "position ASC"
- has_many :leads, :as => :leadable
- has_and_belongs_to_many :tags, :after_add => :increment_counter_cache, :after_remove => :decrement_counter_cache
- has_and_belongs_to_many :email_notifications
- before_create :generate_password
- #hooks
- def before_validation
- super
- if program
- self.availability_date = self.program.delivery_date
- self.address = self.program.address.clone
- self.office_id = self.program.office_id
- self.address.save!
- end
- end
- def after_destroy
- if program
- if program.classifieds.size == 0 and program.is_published == true
- program.is_published = false
- program.save!
- end
- end
- end
- after_save :update_tags
- #global validation
- validates_presence_of :type_of_transaction
- validates_presence_of :user
- validates_associated :user
- validates_presence_of :office
- validates_associated :office
- #specific validation
- validates_presence_of :address
- validates_associated :address
- validates_presence_of :program, :if => Proc.new { |classified| classified.type_of_transaction == 'newly built' }
- validates_associated :program, :if => Proc.new { |classified| classified.type_of_transaction == 'newly built' }
- #behaviour
- strip_tags_attribute :title
- white_list_attribute :description
- define_price_display_attribute :price
- define_price_display_attribute :expenses
- define_price_display_attribute :fees
- def to_param
- "#{id}-#{PermalinkFu.escape(title)}"
- end
- def type_of_good
- self.class.to_s
- end
- def viewable_by?(viewer)
- viewer.organization.classifieds.include?(self)
- end
- def destroyable_by?(deleter)
- (deleter.organization.classifieds.include?(self) && deleter.has_role?("OrganizationAdministratorRole")) ||
- (deleter.has_role?("ClassifiedManagerRole") && deleter.classifieds.include?(self))
- end
- def updatable_by?(updater)
- (updater.organization.classifieds.include?(self) && updater.has_role?("OrganizationAdministratorRole")) ||
- (updater.has_role?("ClassifiedManagerRole") && updater.classifieds.include?(self))
- end
- def localization
- if address
- "#{address.city} (#{address.postal_code})"
- end
- end
- protected
- def generate_password
- self.password = Digest::SHA1.hexdigest("--#{Time.now.to_s}--")
- end
- def validate
- raise "Classified cannot be call directly, use TypeOfGoods classes instead" if self.class.name == 'Classified'
- type_of_good = TypeOfGood.find_by_name(self.class.name)
- raise "class: #{self.class.name} does not inherit of Classified" if type_of_good == nil
- errors.add("type_of_transaction", "'#{type_of_transaction}' is not valid") unless type_of_good.type_of_transactions.map{|t| t.name}.include?(type_of_transaction)
- end
- # return array of keep_translations_in_model db fields for a specific field_name
- def self.keep_translations_in_model_attribute_names(field_name)
- attribute_names = []
- attribute_names = self.column_names.delete_if{|column_name| Language.pick(column_name.match(field_name+"_([a-z][a-z])")[1])==nil rescue true } if self.globalize_facets.include?(field_name.to_sym)
- end
- # construct dynamic validation methods from type_of_good fixtures.yml
- def self.validate_classified()
- type_of_good = TypeOfGood.find_by_name( self.name)
- type_of_good.datafields.each{ |field_name,validators|
- validators.each { |validator_name,validator_args|
- next if (validator_name =~ /^validates_/)!=0
- attr_names = validator_args==nil ? nil : eval(validator_args)
- #default_values hack
- if (validators["default_values"]!=nil and validator_name=="validates_inclusion_of" and (attr_names ==nil or attr_names[:in]==nil))
- default_values_key = "default_values"
- default_values = eval(validators[default_values_key])
- type_of_good.type_of_transactions.each{|t|
- # type_of_transaction-dependent default values hack
- default_values.concat(eval(validators[default_values_key+"_"+t.name])) if validators[default_values_key+"_"+t.name]
- }
- in_hash={:in => default_values.map{|x| x[1]}}
- attr_names = attr_names ==nil ? in_hash : attr_names.merge(in_hash)
- end
- #type_of_transaction hack
- if validators["exclude_for_type_of_transactions"]!=nil
- in_hash={:if => Proc.new { |classified| validators["exclude_for_type_of_transactions"].include?(classified.type_of_transaction) ==false }}
- attr_names = attr_names ==nil ? in_hash : attr_names.merge(in_hash)
- end
- if self.globalize_facets.include?(field_name.to_sym)
- #for translated attributes (globalize keep_translations_in_model)
- self.keep_translations_in_model_attribute_names(field_name).each{|internationalize_field_name|
- language = internationalize_field_name.slice(field_name.length+1,internationalize_field_name.length)
- internationalize_attr_names = attr_names
- begin
- Locale.base_language
- rescue Globalize::NoBaseLanguageError
- #for doc:diagrams
- Locale.set_base_language("fr-FR")
- Locale.set('fr-FR')
- end
- if (language != Locale.base_language.code)
- #other language than base_language are not mandatory
- if (validator_name == 'validates_presence_of')
- next #skip presence_of (cannot set it to :allow_ni)
- else
- in_hash={:allow_nil => true}
- internationalize_attr_names = internationalize_attr_names ==nil ? in_hash : internationalize_attr_names.merge(in_hash)
- end
- end
- if internationalize_attr_names==nil
- send(validator_name.to_sym,internationalize_field_name.to_sym)
- else
- send(validator_name.to_sym,internationalize_field_name.to_sym,internationalize_attr_names)
- end
- }
- else
- # classic field
- if attr_names==nil
- send(validator_name.to_sym,field_name.to_sym)
- else
- send(validator_name.to_sym,field_name.to_sym,attr_names)
- end
- end
- } unless validators == nil
- }
- end
- def update_tags
- if @new_tag_list
- Tag.transaction do
- tags.clear
- Tag.parse(@new_tag_list).each do |name|
- tag = Tag.find_or_create_by_name(name)
- tags << tag
- end
- tags.reset
- @new_tag_list = nil
- end
- end
- end
- def increment_counter_cache(tag)
- organization_tag = OrganizationTag.find_or_create_by_organization_id_and_tag_id(office.organization.id, tag.id)
- OrganizationTag.increment_counter('organization_count', organization_tag.id)
- end
- def decrement_counter_cache(tag)
- organization_tag = OrganizationTag.find_or_create_by_organization_id_and_tag_id(office.organization.id, tag.id)
- OrganizationTag.decrement_counter('organization_count', organization_tag.id)
- end
- public
- def tag_list
- tags.collect{|tag| tag.name.include?(" ") ? %("#{tag.name}") : tag.name }.join(" ")
- end
- def tag_list=(new_tag_list)
- unless tag_list == new_tag_list
- @new_tag_list = new_tag_list
- end
- end
- # factory to instanciate House Apartement, and all TypeOfGood Classified classes through 'type' attribute
- def self.create(attributes)
- my_class = nil
- unless attributes[:type] == nil
- class_name = attributes[:type]
- attributes.delete(:type)
- my_class = class_name.constantize.new(attributes)
- end
- my_class
- end
- def initialize(attributes = nil)
- if self.class.name != 'Classified' and attributes !=nil
- # allow_nil hack (to set to nil not mandatory blank attribute in order to pass validators)
- self.class.non_mandatory_fields(attributes[:type_of_transaction]).each{ |non_mandatory_field|
- if self.class.globalize_facets.include?(non_mandatory_field.to_sym)
- # for translated attributes (globalize keep_translations_in_model)
- self.class.keep_translations_in_model_attribute_names(non_mandatory_field).each { |internationalized_attribute_name|
- attributes[internationalized_attribute_name.to_sym] = nil if attributes.has_key?(internationalized_attribute_name.to_sym) and attributes[internationalized_attribute_name.to_sym].blank?
- }
- else
- # for classic attributes
- attributes[non_mandatory_field.to_sym] = nil if attributes.has_key?(non_mandatory_field.to_sym) and attributes[non_mandatory_field.to_sym].blank?
- end
- }
- end
- super(attributes)
- end
- def self.field_type(field_name,class_name=self.name)
- type_of_good = TypeOfGood.find_by_name(class_name)
- type_of_good.datafields[field_name]["field_type"] unless type_of_good == nil or type_of_good.datafields[field_name] ==nil
- end
- def self.default_values?(field_name,class_name=self.name,type_of_default_values=nil)
- default_values_key = "default_values"
- default_values_key += "_"+type_of_default_values if type_of_default_values
- type_of_good = TypeOfGood.find_by_name(class_name)
- type_of_good != nil and type_of_good.datafields[field_name.to_s] !=nil and type_of_good.datafields[field_name.to_s][default_values_key].blank? ==false
- end
- # return field_name default value depending on return_type:
- # return_type = nil (default) - an ordered array of [[default_label , default_value],...]
- # return_type = 'keys' - an ordered array of [default_label, default_label2,...]
- # return_type = 'values' - an ordered array of [default_value, default_value2,...]
- # return_type = 'Hash' - an non-ordered Hash of {default_label => default_value,...}
- # return_type = 'Hash' - an non-ordered Hash of {default_label => default_value,...}
- # class_name = "Apartment", "House", ... all child class name of Classified
- # type_of_default_values - instead of using global 'default_values' use a specific default_values_<type_of_default_values> list entry (see type_of_goods.yml)
- # options
- # - :override_allow_nil_label allow to replace label of ["Sélectionnez une valeur", nil] by ["<override_allow_nil_label value>", nil]
- #
- # Examples:
- # >> Classified.default_values("number_of_bedrooms",nil,"Apartment")
- # => [["Sélectionnez une valeur", nil], ["1", 1], ["2", 2], ["3", 3], ["4", 4], ["5+", 5]]
- #
- # >> Classified.default_values("number_of_bedrooms",Hash,"Apartment")
- # => {"5+"=>5, "Sélectionnez une valeur"=>nil, "1"=>1, "2"=>2, "3"=>3, "4"=>4}
- #
- # >> Classified.default_values("price_frequency",Hash,"Field","rental")
- # >> Classified.default_values("price_frequency",Hash,"*","*")
- # =>
- # find all type type of default values for field "price_frequency" for each TypeOfGood and TypeOfTransaction
- def self.default_values(field_name,return_type=nil,class_name=self.name,type_of_default_value=nil,options={})
- return_values =[]
- if class_name=='*'
- class_names= TypeOfGood.find(:all).map{|t| t.name}
- else
- class_names=[class_name]
- end
- if type_of_default_value=='*'
- type_of_default_values=TypeOfTransaction.find(:all).map{|t| t.name}
- type_of_default_values.unshift(nil)
- else
- type_of_default_values=[type_of_default_value]
- end
- class_names.each{|class_name|
- default_values = {}
- type_of_good = TypeOfGood.find_by_name(class_name)
- type_of_default_values.each{|type_of_default_value|
- default_values_key = "default_values"
- default_values_key += "_"+type_of_default_value if type_of_default_value
- value = type_of_good.datafields[field_name.to_s][default_values_key] unless type_of_good == nil or type_of_good.datafields[field_name.to_s] ==nil
- unless value ==nil
- default_values = eval(value)
- default_values = default_values.map{|item| item[1]==nil ? [options[:override_allow_nil_label],nil] : [item[0],item[1]]} if options[:override_allow_nil_label]
- end
- if default_values.size>0
- case return_type.to_s
- when "" #nil.to_s
- return_values << default_values if return_type==nil
- when Hash.name
- return_values << Hash[*default_values.flatten]
- when "keys"
- return_values << default_values.map{|x| x[0]}
- when "values"
- return_values << default_values.map{|x| x[1]}
- else
- raise "bad return_type (#{return_type}) for Classified.default_value"
- end
- end
- }
- }
- return_values = return_values[0] if return_values.size==1
- return_values = {} if return_values.size == 0 and return_type.to_s == Hash.name
- return return_values
- end
- # return field_name default_values (based on classified type_of_transaction)
- # see self.default_values
- def default_values(field_name,return_type=nil)
- if self.class.default_values?(field_name,self.class.name,type_of_transaction)
- type_of_default_values = type_of_transaction
- else
- type_of_default_values = nil
- end
- self.class.default_values(field_name,return_type,self.class.name,type_of_default_values)
- end
- # when field_name has default_values? map value to default value 'label', otherwise display value
- def display_value_map(field_name)
- if respond_to?(field_name)
- value = send(field_name)
- hash = default_values(field_name,Hash).invert
- value = hash[value] if hash[value]
- end
- value
- end
- # return a hash of [data_fields_name => is_field_mandatory (true or false)], if type_of_transaction = nil or not found it return complete datafield list
- def self.datafields(type_of_transaction=nil)
- fields_info = {}
- type_of_good = TypeOfGood.find_by_name( self.name)
- type_of_good.datafields.each{ |field_name,validators|
- unless (validators != nil and validators["exclude_for_type_of_transactions"] != nil and validators["exclude_for_type_of_transactions"].include?(type_of_transaction))
- mandatory = false
- if (validators !=nil)
- mandatory = true
- count_allow_nil = 0
- validators.each { |validator_name,validator_args|
- if (validator_name =~ /^validates_/)!=0
- count_allow_nil = count_allow_nil+1
- next
- end
- attr_names = validator_args==nil ? nil : eval(validator_args)
- count_allow_nil = count_allow_nil+1 if attr_names != nil and attr_names[:allow_nil] == true
- }
- mandatory = false if validators.size == count_allow_nil
- end
- fields_info[field_name] = mandatory
- end
- }
- fields_info
- end
- # see self.datafields
- def datafields
- self.class.datafields(type_of_transaction)
- end
- # return a array of non_mandatory fields
- def self.non_mandatory_fields(type_of_transaction=nil)
- self.datafields(type_of_transaction).delete_if {|field_name,mandatory| mandatory==true }.keys
- end
- # see self.non_mandatory_fields
- def non_mandatory_fields
- self.class.non_mandatory_fields(type_of_transaction)
- end
- # return a array of mandatory fields
- def self.mandatory_fields(type_of_transaction=nil)
- self.datafields(type_of_transaction).delete_if {|field_name,mandatory| mandatory==false }.keys
- end
- # see self.mandatory_fields
- def mandatory_fields
- self.class.mandatory_fields(type_of_transaction)
- end
- # return a array of displayed fields
- def self.displayed_fields(type_of_transaction=nil)
- self.datafields(type_of_transaction).keys
- end
- # see self.displayed_fields
- def displayed_fields
- self.class.displayed_fields(type_of_transaction)
- end
- # check if field_name is displayable depending of type_of_transaction
- def self.displayable_field(type_of_transaction,field_name)
- self.datafields(type_of_transaction).keys.include?(field_name.to_s)
- end
- # see self.displayable_field
- def displayable_field(field_name,false_if_empty=false)
- return false if false_if_empty and send(field_name)==nil
- self.class.displayable_field(type_of_transaction,field_name)
- end
- # check if field_name is mandatory depending of type_of_transaction
- def self.mandatory_field(type_of_transaction,field_name)
- self.mandatory_fields(type_of_transaction).include?(field_name.to_s)
- end
- # see self.mandatory_field
- def mandatory_field(field_name)
- self.class.mandatory_field(type_of_transaction,field_name)
- end
- # provide an array of all TypeOfGood datafields
- def self.all_datafields
- fixtures_data = YAML::load_file(self::DataFieldsFilePath)
- end
- # see self.all_datafields
- def all_datafields
- self.class.all_datafields
- end
- # tell for all_adatafields if [fieldname => is displayable]
- def fields_displayability
- fields_displayability = {}
- displayed_fields = displayed_fields()
- all_datafields.each{ |field| fields_displayability[field] = displayed_fields.include?(field)}
- fields_displayability
- end
- def user_id=(value)
- super(value)
- self.user = User.find(value) if !value.blank?
- self[:user_id]=value
- end
- def office_id=(value)
- super(value)
- self.office = Office.find(self[:office_id]) if !value.blank?
- end
- def program_id=(value)
- super(value)
- self.program = Program.find(self[:program_id]) if !value.blank?
- end
- #always convert to square meters
- def area_size=(value)
- begin
- Kernel.Float(value) # test numeric value
- self[:area_size] = value.to_i.send(Locale.active.country.area_size_unit).to_square_meters.value
- rescue ArgumentError, TypeError
- self[:area_size] = value #pass raw value to validator
- end
- end
- #always convert to square meters
- def lot_size=(value)
- begin
- Kernel.Float(value) # test numeric value
- self[:lot_size] = value.to_i.send(Locale.active.country.lot_size_unit).to_square_meters.value
- rescue ArgumentError, TypeError
- self[:lot_size] = value #pass raw value to validator
- end
- end
- def area_size_localized
- begin
- self[:area_size].square_meters.send(Locale.active.country.area_size_unit).value.to_i
- rescue
- self[:area_size]
- end
- end
- def lot_size_localized
- begin
- self[:lot_size].square_meters.send(Locale.active.country.lot_size_unit).value.to_i
- rescue
- self[:lot_size]
- end
- end
- end
- # {attr_name}_display magic method
- Classified.class_eval do
- self.all_datafields.each {|attr_name|
- next if self.method_defined?("#{attr_name}_display".to_sym)
- define_method("#{attr_name}_display".to_sym) {
- display_value_map(attr_name)
- }
- }
- end
Add Comment
Please, Sign In to add comment