Build Status

Gem designed to allow easy addition of eLibri based product to your application.

Working under 1.8, ree and 1.9.3 version of Ruby

Usage guide:

  • Add 'acts_as_elibri_product' to your Gemfile

  • Run rails g add_acts_as_elibri_product [YOUR_PRODUCT_MODEL_NAME]

  • Run rake db:migrate

  • Add acts_as_elibri_product TRAVERSE_VECTOR to your product_model

  • Schedule (for example in cron) regular calls to ProductModel.batch_create_or_update_from_elibri providing xml_string from eLibri API as an argument, or providing Elibri::ONIX::Release_3_0::ONIXMessage from eLibri API as an argument.

TRAVERSE_VECTOR is a structure containing information about mapping elibri arguments to your model arguments. Attributes not specified here, will be ignored during data import.

Structure is build using hashes, general rule is:

{
:elibri_attribute_name => :application_attribute_name,  
:another_elibri_attribute_name => :another_application_attribute_name
}

Also you can use lambda in this construction, if you want to do something with attribute (for example downcase it). In this case, you should use array, where first element is name of elibri attribute and second element is lambda that describes what to do with it.

Example:

{
  :title => [:title, lambda {|product, value| Logger.info("changing title"); return "#{x}_test"}]
} 

Important thing is that lambda need to take exactly two arguments (first one will be product that are updating / creating right now, second will be value of field), and need to return final value of attribute to write into database.
Also very important thing is that lambdas are now supported only on first level of vector (not in embedded hashes).

If you want to use lambda, but don't write anything to database, you should use nil as first attribute in array. For example:
```ruby
{
 :title => [nil, lambda {|product, value| Logger.info("changing title") } ]
}

When dealing with embedded objects and relations, you should use embedded hashes:  

```ruby
:elibri_embedded_object_name =>  
  { :application_relations_name =>    
    {  
      :embedded_object_elibri_attribute_name => :application_relation_object_attribute_name,  
      :another_embedded_object_elibri_attribute_name => :another_application_relation_object_attribute_name     
    }      
  }

In embedded object, id may change, however import_id and/or record_reference will always remain unchanged.

example vector:

:record_reference => :record_reference,
:isbn13 => :isbn,
:title => :title,
:full_title => :full_title,
:trade_title => :trade_title,
:original_title => :original_title,
:number_of_pages => :number_of_pages,
:duration => :duration,
:width => :width,
:height => :height,
:cover_type => :cover_type,
:pkwiu => :pkwiu,
:edition_statement => :edition_statement,
:reading_age_from => :audience_age_from,
:reading_age_to => :audience_age_to,
:cover_price => :price_amount,
:vat => :vat,
:product_form => :product_form,
:no_contributor? => :no_contributor,
:unnamed_persons? => :unnamed_persons,
:contributors => { #embedded name in elibri
 :contributors => { #embedded name in elibri
   :id => :import_id, #name transition atrybutow elibri => our app
   :role_name => :role_name,
   :role => :role,
   :from_language => :from_language,
   :person_name => :full_name,
   :titles_before_names => :title,
   :names_before_key => :first_name,
   :prefix_to_key => :last_name_prefix,
   :key_names => :last_name,
   :names_after_key => :last_name_postfix,
   :biographical_note => :biography
 }
},
:text_contents => { #embedded name in elibri
 :product_texts => { #embedded name in elibri
   :id => :import_id, #name transition atrybutow elibri => our app
   :text => :text,
   :type_name => :text_type,
   :author => :text_author,
   :source_title => :source_title,
   :source_url => :resource_link
 }
},
:imprint => {
 :imprint => {
   :name => :name
 }
},
:related_products => {
  :related_products => {
    :record_reference => :related_record_reference,
    :relation_code => :onix_code
  }
},
:front_cover => [
  nil,
  lambda do |product, cover_class|
    product.send(:write_attribute, :cover_link, cover_class.link) if cover_class
  end
  ] #we enter link to cover in field - however remember that hotlinking from eLibri is forbidden - this is just an example

Also if you want to check for some particular changes in object - you can use policy chain.

policy_chain << PolicyObject
policy_chain << lambda

PolicyObject must implement class method call, which take four arguments:

  • object is symbol of object that inside which attribute is changing - it should be our name, not elibri one, for example on main level it would :product, inside contributors it will be :contributors etc.

  • attribute is symbol of attribute that will change - it should be our name, not elibri one

  • pre - value of attribute before potential update

  • post - value of attribute after potential update

Also policy must return one of two values - true (if allow of changing an attribute) or false (if attribute should remain unchanged). You can implement notification etc inside Policy, when attribute is discarded - it's up to you.

example of Policy (stub):

module Policy #module is optional - however it is good practice to keep all policies in Policy module, and in subdirectory inside lib
  class Stub

    def self.call(object, attribute, pre, post)
      ### Add policy body here
      return true
    end

  end
end

example of adding policy lambda:
```ruby
policy_chain << lambda do |object, attribute, pre, post|
   if object == :product
     if attribute == :price_amount
       return false unless pre == post #won't allow change of product price
     end
   end
   return true
 end