diff --git a/app/models/scopes/template_scope.rb b/app/models/scopes/template_scope.rb deleted file mode 100644 index 1f5556f..0000000 --- a/app/models/scopes/template_scope.rb +++ /dev/null @@ -1,90 +0,0 @@ -require 'active_support/concern' - -module TemplateScope - extend ActiveSupport::Concern - - included do - scope :archived, -> { where(archived: true) } - scope :unarchived, -> { where(archived: false) } -# scope :default, -> { published(where(is_default: true).last) } - scope :default, -> { where(is_default: true, published: true).last } - scope :published, -> (family_id = nil) { - if family_id.present? - unarchived.where(published: true, family_id: family_id) - else - unarchived.where(published: true) - end - } - - # Retrieves the latest templates, i.e. those with maximum version associated. It can be filtered down - # if family_id is passed. NOTE, the template objects instantiated only contain version and family attributes - # populated. See Template::latest_version scope method for an adequate instantiation of template instances - scope :latest_version_per_family, -> (family_id = nil) { - chained_scope = unarchived.select("MAX(version) AS version", :family_id) - if family_id.present? - chained_scope = chained_scope.where(family_id: family_id) - end - chained_scope.group(:family_id) - } - scope :latest_customized_version_per_customised_of, -> (customization_of=nil, org_id = nil) { - chained_scope = select("MAX(version) AS version", :customization_of) - chained_scope = chained_scope.where(customization_of: customization_of) - if org_id.present? - chained_scope = chained_scope.where(org_id: org_id) - end - chained_scope.group(:customization_of) - } - # Retrieves the latest templates, i.e. those with maximum version associated. It can be filtered down - # if family_id is passed - scope :latest_version, -> (family_id = nil) { - unarchived.from(latest_version_per_family(family_id), :current) - .joins("INNER JOIN templates ON current.version = templates.version " + - "AND current.family_id = templates.family_id INNER JOIN orgs ON orgs.id = templates.org_id") - } - # Retrieves the latest customized versions, i.e. those with maximum version associated for a set - # of family_id and an org - scope :latest_customized_version, -> (family_id = nil, org_id = nil) { - unarchived.from(latest_customized_version_per_customised_of(family_id, org_id), :current) - .joins("INNER JOIN templates ON current.version = templates.version"\ - " AND current.customization_of = templates.customization_of INNER JOIN orgs ON orgs.id = templates.org_id") - .where(templates: { org_id: org_id }) - } - # Retrieves the latest templates, i.e. those with maximum version associated for a set of org_id passed - scope :latest_version_per_org, -> (org_id = nil) { - if org_id.respond_to?(:each) - family_ids = families(org_id).pluck(:family_id) - else - family_ids = families([org_id]).pluck(:family_id) - end - latest_version(family_ids) - } - # Retrieve all of the latest customizations for the specified org - scope :latest_customized_version_per_org, -> (org_id=nil) { - family_ids = families(org_id).pluck(:family_id) - latest_customized_version(family_ids, org_id) - } - # Retrieves templates with distinct family_id. It can be filtered down if org_id is passed - scope :families, -> (org_id=nil) { - if org_id.respond_to?(:each) - unarchived.where(org_id: org_id, customization_of: nil).distinct - else - unarchived.where(customization_of: nil).distinct - end - } - # Retrieves the latest version of each customizable funder template (and the default template) - scope :latest_customizable, -> { - family_ids = families(Org.funder.collect(&:id)).distinct.pluck(:family_id) << default.family_id - published(family_ids.flatten).where('visibility = ? OR is_default = ?', visibilities[:publicly_visible], true) - } - # Retrieves unarchived templates with public visibility - scope :publicly_visible, -> { unarchived.where(:visibility => visibilities[:publicly_visible]) } - # Retrieves unarchived templates with organisational visibility - scope :organisationally_visible, -> { unarchived.where(:visibility => visibilities[:organisationally_visible]) } - # Retrieves unarchived templates whose title or org.name includes the term passed - scope :search, -> (term) { - search_pattern = "%#{term}%" - unarchived.where("templates.title LIKE ? OR orgs.name LIKE ?", search_pattern, search_pattern) - } - end -end - diff --git a/app/models/template.rb b/app/models/template.rb index 7c55b56..58728d1 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -1,7 +1,7 @@ class Template < ActiveRecord::Base include GlobalHelpers include ActiveModel::Validations - include TemplateScope + validates_with TemplateLinksValidator before_validation :set_defaults @@ -21,6 +21,123 @@ has_many :annotations, through: :questions + # ========== + # = Scopes = + # ========== + + scope :archived, -> { where(archived: true) } + + scope :unarchived, -> { where(archived: false) } + + scope :default, -> { where(is_default: true, published: true).last } + + scope :published, -> (family_id = nil) { + if family_id.present? + unarchived.where(published: true, family_id: family_id) + else + unarchived.where(published: true) + end + } + + # Retrieves the latest templates, i.e. those with maximum version associated. + # It can be filtered down if family_id is passed. NOTE, the template objects + # instantiated only contain version and family attributes populated. See + # Template::latest_version scope method for an adequate instantiation of + # template instances. + scope :latest_version_per_family, -> (family_id = nil) { + chained_scope = unarchived.select("MAX(version) AS version", :family_id) + if family_id.present? + chained_scope = chained_scope.where(family_id: family_id) + end + chained_scope.group(:family_id) + } + + scope :latest_customized_version_per_customised_of, -> (customization_of=nil, + org_id = nil) { + chained_scope = select("MAX(version) AS version", :customization_of) + chained_scope = chained_scope.where(customization_of: customization_of) + if org_id.present? + chained_scope = chained_scope.where(org_id: org_id) + end + chained_scope.group(:customization_of) + } + + # Retrieves the latest templates, i.e. those with maximum version associated. + # It can be filtered down if family_id is passed + scope :latest_version, -> (family_id = nil) { + unarchived.from(latest_version_per_family(family_id), :current) + .joins(<<~SQL) + INNER JOIN templates ON current.version = templates.version + AND current.family_id = templates.family_id + INNER JOIN orgs ON orgs.id = templates.org_id + SQL + } + + # Retrieves the latest customized versions, i.e. those with maximum version + # associated for a set of family_id and an org + scope :latest_customized_version, -> (family_id = nil, org_id = nil) { + unarchived + .from(latest_customized_version_per_customised_of(family_id, org_id), + :current) + .joins(<<~SQL) + INNER JOIN templates ON current.version = templates.version + AND current.customization_of = templates.customization_of + INNER JOIN orgs ON orgs.id = templates.org_id + SQL + .where(templates: { org_id: org_id }) + } + + # Retrieves the latest templates, i.e. those with maximum version associated + # for a set of org_id passed + scope :latest_version_per_org, -> (org_id = nil) { + if org_id.respond_to?(:each) + family_ids = families(org_id).pluck(:family_id) + else + family_ids = families([org_id]).pluck(:family_id) + end + latest_version(family_ids) + } + + # Retrieve all of the latest customizations for the specified org + scope :latest_customized_version_per_org, -> (org_id=nil) { + family_ids = families(org_id).pluck(:family_id) + latest_customized_version(family_ids, org_id) + } + + # Retrieves templates with distinct family_id. It can be filtered down if + # org_id is passed + scope :families, -> (org_id=nil) { + if org_id.respond_to?(:each) + unarchived.where(org_id: org_id, customization_of: nil).distinct + else + unarchived.where(customization_of: nil).distinct + end + } + + # Retrieves the latest version of each customizable funder template (and the + # default template) + scope :latest_customizable, -> { + family_ids = families(Org.funder.collect(&:id)).distinct.pluck(:family_id) << default.family_id + published(family_ids.flatten).where('visibility = ? OR is_default = ?', visibilities[:publicly_visible], true) + } + + # Retrieves unarchived templates with public visibility + scope :publicly_visible, -> { + unarchived.where(visibility: visibilities[:publicly_visible]) + } + + # Retrieves unarchived templates with organisational visibility + scope :organisationally_visible, -> { + unarchived.where(visibility: visibilities[:organisationally_visible]) + } + + # Retrieves unarchived templates whose title or org.name includes the term + # passed + scope :search, -> (term) { + unarchived.where("templates.title LIKE :term OR orgs.name LIKE :term", + { term: "%#{term}%" }) + } + # A standard template should be organisationally visible. Funder templates that are # meant for external use will be publicly visible. This allows a funder to create 'funder' as # well as organisational templates. The default template should also always be publicly_visible diff --git a/config/application.rb b/config/application.rb index d79b06e..2d550cb 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,7 +40,6 @@ # Enable escaping HTML in JSON. config.active_support.escape_html_entities_in_json = true - config.eager_load_paths << "app/models/scopes" config.eager_load_paths << "app/services" # Use SQL instead of Active Record's schema dumper when creating the database. @@ -48,6 +47,12 @@ # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql + # Enforce whitelist mode for mass assignment. + # This will create an empty whitelist of attributes available for mass-assignment for all models + # in your app. As such, your models will need to explicitly whitelist or blacklist accessible + # parameters by using an attr_accessible or attr_protected declaration. + #config.active_record.whitelist_attributes = true + config.autoload_paths += %W(#{config.root}/lib) config.action_controller.include_all_helpers = true