summaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2014-10-22 17:37:16 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2014-10-22 17:37:16 +0000
commit2d1866d966d94c688f9cb87c5bf3f096dffac844 (patch)
tree7a733c1cc51448ab69b3f892285305dbfb0ae15e /app/models
parenta6ec78a4dc658e3517ed682792016b6530458696 (diff)
downloadredmine-2d1866d966d94c688f9cb87c5bf3f096dffac844.tar.gz
redmine-2d1866d966d94c688f9cb87c5bf3f096dffac844.zip
Merged rails-4.1 branch (#14534).
git-svn-id: http://svn.redmine.org/redmine/trunk@13482 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app/models')
-rw-r--r--app/models/attachment.rb15
-rw-r--r--app/models/auth_source.rb1
-rw-r--r--app/models/board.rb9
-rw-r--r--app/models/change.rb1
-rw-r--r--app/models/changeset.rb9
-rw-r--r--app/models/comment.rb1
-rw-r--r--app/models/custom_field.rb5
-rw-r--r--app/models/custom_value.rb1
-rw-r--r--app/models/document.rb10
-rw-r--r--app/models/enabled_module.rb1
-rw-r--r--app/models/enumeration.rb2
-rw-r--r--app/models/group.rb8
-rw-r--r--app/models/group_anonymous.rb4
-rw-r--r--app/models/group_builtin.rb2
-rw-r--r--app/models/group_non_member.rb4
-rw-r--r--app/models/issue.rb75
-rw-r--r--app/models/issue_category.rb1
-rw-r--r--app/models/issue_custom_field.rb2
-rw-r--r--app/models/issue_query.rb34
-rw-r--r--app/models/issue_status.rb3
-rw-r--r--app/models/journal.rb12
-rw-r--r--app/models/journal_detail.rb1
-rw-r--r--app/models/mail_handler.rb4
-rw-r--r--app/models/member.rb1
-rw-r--r--app/models/member_role.rb1
-rw-r--r--app/models/message.rb9
-rw-r--r--app/models/news.rb14
-rw-r--r--app/models/principal.rb16
-rw-r--r--app/models/project.rb66
-rw-r--r--app/models/query.rb20
-rw-r--r--app/models/repository.rb16
-rw-r--r--app/models/repository/cvs.rb2
-rw-r--r--app/models/repository/git.rb2
-rw-r--r--app/models/repository/mercurial.rb5
-rw-r--r--app/models/repository/subversion.rb2
-rw-r--r--app/models/role.rb2
-rw-r--r--app/models/setting.rb2
-rw-r--r--app/models/time_entry.rb14
-rw-r--r--app/models/time_entry_query.rb5
-rw-r--r--app/models/token.rb1
-rw-r--r--app/models/tracker.rb4
-rw-r--r--app/models/user.rb35
-rw-r--r--app/models/version.rb10
-rw-r--r--app/models/watcher.rb1
-rw-r--r--app/models/wiki.rb3
-rw-r--r--app/models/wiki_content.rb17
-rw-r--r--app/models/wiki_page.rb13
-rw-r--r--app/models/wiki_redirect.rb1
-rw-r--r--app/models/workflow_rule.rb3
-rw-r--r--app/models/workflow_transition.rb2
50 files changed, 283 insertions, 189 deletions
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index f36f7cccf..9d7e03247 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -27,6 +27,7 @@ class Attachment < ActiveRecord::Base
validates_length_of :disk_filename, :maximum => 255
validates_length_of :description, :maximum => 255
validate :validate_max_file_size
+ attr_protected :id
acts_as_event :title => :filename,
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
@@ -34,16 +35,16 @@ class Attachment < ActiveRecord::Base
acts_as_activity_provider :type => 'files',
:permission => :view_files,
:author_key => :author_id,
- :find_options => {:select => "#{Attachment.table_name}.*",
- :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
- "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"}
+ :scope => select("#{Attachment.table_name}.*").
+ joins("LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
+ "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )")
acts_as_activity_provider :type => 'documents',
:permission => :view_documents,
:author_key => :author_id,
- :find_options => {:select => "#{Attachment.table_name}.*",
- :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
- "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
+ :scope => select("#{Attachment.table_name}.*").
+ joins("LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
+ "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id")
cattr_accessor :storage_path
@@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files")
@@ -74,7 +75,7 @@ class Attachment < ActiveRecord::Base
if @temp_file.size > 0
if @temp_file.respond_to?(:original_filename)
self.filename = @temp_file.original_filename
- self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding)
+ self.filename.force_encoding("UTF-8")
end
if @temp_file.respond_to?(:content_type)
self.content_type = @temp_file.content_type.to_s.chomp
diff --git a/app/models/auth_source.rb b/app/models/auth_source.rb
index 1494e161a..aa2506e5b 100644
--- a/app/models/auth_source.rb
+++ b/app/models/auth_source.rb
@@ -29,6 +29,7 @@ class AuthSource < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
validates_length_of :name, :maximum => 60
+ attr_protected :id
def authenticate(login, password)
end
diff --git a/app/models/board.rb b/app/models/board.rb
index 387792cb4..2cbeb0a8a 100644
--- a/app/models/board.rb
+++ b/app/models/board.rb
@@ -18,8 +18,8 @@
class Board < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project
- has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC"
- has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC"
+ has_many :topics, lambda {where("#{Message.table_name}.parent_id IS NULL").order("#{Message.table_name}.created_on DESC")}, :class_name => 'Message'
+ has_many :messages, lambda {order("#{Message.table_name}.created_on DESC")}, :dependent => :destroy
belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id
acts_as_tree :dependent => :nullify
acts_as_list :scope => '(project_id = #{project_id} AND parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"})'
@@ -29,9 +29,12 @@ class Board < ActiveRecord::Base
validates_length_of :name, :maximum => 30
validates_length_of :description, :maximum => 255
validate :validate_board
+ attr_protected :id
scope :visible, lambda {|*args|
- includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
+ joins(:project).
+ references(:project).
+ where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
}
safe_attributes 'name', 'description', 'parent_id', 'move_to'
diff --git a/app/models/change.rb b/app/models/change.rb
index 6ef56e0de..b24c1bd54 100644
--- a/app/models/change.rb
+++ b/app/models/change.rb
@@ -21,6 +21,7 @@ class Change < ActiveRecord::Base
validates_presence_of :changeset_id, :action, :path
before_save :init_path
before_validation :replace_invalid_utf8_of_path
+ attr_protected :id
def relative_path
changeset.repository.relative_path(path)
diff --git a/app/models/changeset.rb b/app/models/changeset.rb
index cf58c6e07..b12ea6778 100644
--- a/app/models/changeset.rb
+++ b/app/models/changeset.rb
@@ -35,20 +35,23 @@ class Changeset < ActiveRecord::Base
:url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}}
acts_as_searchable :columns => 'comments',
- :include => {:repository => :project},
+ :scope => preload(:repository => :project),
:project_key => "#{Repository.table_name}.project_id",
:date_column => 'committed_on'
acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
:author_key => :user_id,
- :find_options => {:include => [:user, {:repository => :project}]}
+ :scope => preload(:user, {:repository => :project})
validates_presence_of :repository_id, :revision, :committed_on, :commit_date
validates_uniqueness_of :revision, :scope => :repository_id
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
+ attr_protected :id
scope :visible, lambda {|*args|
- includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
+ joins(:repository => :project).
+ references(:repository => :project).
+ where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
}
after_create :scan_for_issues
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 02d9a3b36..9893ad664 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -21,6 +21,7 @@ class Comment < ActiveRecord::Base
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :commented, :author, :comments
+ attr_protected :id
after_create :send_notification
diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb
index 48ef2c7cc..f3829bf70 100644
--- a/app/models/custom_field.rb
+++ b/app/models/custom_field.rb
@@ -29,6 +29,7 @@ class CustomField < ActiveRecord::Base
validates_length_of :name, :maximum => 30
validates_inclusion_of :field_format, :in => Proc.new { Redmine::FieldFormat.available_formats }
validate :validate_custom_field
+ attr_protected :id
before_validation :set_searchable
before_save do |field|
@@ -117,7 +118,7 @@ class CustomField < ActiveRecord::Base
values = read_attribute(:possible_values)
if values.is_a?(Array)
values.each do |value|
- value.force_encoding('UTF-8') if value.respond_to?(:force_encoding)
+ value.force_encoding('UTF-8')
end
values
else
@@ -218,7 +219,7 @@ class CustomField < ActiveRecord::Base
# to move in project_custom_field
def self.for_all
- where(:is_for_all => true).order('position').all
+ where(:is_for_all => true).order('position').to_a
end
def type_name
diff --git a/app/models/custom_value.rb b/app/models/custom_value.rb
index 952646311..ab2eee744 100644
--- a/app/models/custom_value.rb
+++ b/app/models/custom_value.rb
@@ -18,6 +18,7 @@
class CustomValue < ActiveRecord::Base
belongs_to :custom_field
belongs_to :customized, :polymorphic => true
+ attr_protected :id
def initialize(attributes=nil, *args)
super
diff --git a/app/models/document.rb b/app/models/document.rb
index 4609d8602..c195f64ca 100644
--- a/app/models/document.rb
+++ b/app/models/document.rb
@@ -21,19 +21,23 @@ class Document < ActiveRecord::Base
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
acts_as_attachable :delete_permission => :delete_documents
- acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
+ acts_as_searchable :columns => ['title', "#{table_name}.description"],
+ :scope => preload(:project)
acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
:author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
:url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
- acts_as_activity_provider :find_options => {:include => :project}
+ acts_as_activity_provider :scope => preload(:project)
validates_presence_of :project, :title, :category
validates_length_of :title, :maximum => 60
+ attr_protected :id
after_create :send_notification
scope :visible, lambda {|*args|
- includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
+ joins(:project).
+ references(:project).
+ where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
}
safe_attributes 'category_id', 'title', 'description'
diff --git a/app/models/enabled_module.rb b/app/models/enabled_module.rb
index 1cc84aaa5..baf6cdd11 100644
--- a/app/models/enabled_module.rb
+++ b/app/models/enabled_module.rb
@@ -21,6 +21,7 @@ class EnabledModule < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name, :scope => :project_id
+ attr_protected :id
after_create :module_enabled
diff --git a/app/models/enumeration.rb b/app/models/enumeration.rb
index b4b64b7fc..8c82a0dc8 100644
--- a/app/models/enumeration.rb
+++ b/app/models/enumeration.rb
@@ -18,7 +18,7 @@
class Enumeration < ActiveRecord::Base
include Redmine::SubclassFactory
- default_scope :order => "#{Enumeration.table_name}.position ASC"
+ default_scope lambda {order("#{Enumeration.table_name}.position ASC")}
belongs_to :project
diff --git a/app/models/group.rb b/app/models/group.rb
index 7b82d1c1f..b9d4d9ef4 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -28,6 +28,7 @@ class Group < Principal
validates_presence_of :lastname
validates_uniqueness_of :lastname, :case_sensitive => false
validates_length_of :lastname, :maximum => 255
+ attr_protected :id
before_destroy :remove_references_before_destroy
@@ -81,7 +82,8 @@ class Group < Principal
def user_removed(user)
members.each do |member|
MemberRole.
- includes(:member).
+ joins(:member).
+ references(:member).
where("#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids).
each(&:destroy)
end
@@ -95,10 +97,6 @@ class Group < Principal
super(attr_name, *args)
end
- def self.builtin_id(arg)
- (arg.anonymous? ? GroupAnonymous : GroupNonMember).instance_id
- end
-
def self.anonymous
GroupAnonymous.load_instance
end
diff --git a/app/models/group_anonymous.rb b/app/models/group_anonymous.rb
index c3c821bb2..a6d01853d 100644
--- a/app/models/group_anonymous.rb
+++ b/app/models/group_anonymous.rb
@@ -23,8 +23,4 @@ class GroupAnonymous < GroupBuiltin
def builtin_type
"anonymous"
end
-
- def self.instance_id
- @@instance_id ||= load_instance.id
- end
end
diff --git a/app/models/group_builtin.rb b/app/models/group_builtin.rb
index 71ecc06ab..538a89eea 100644
--- a/app/models/group_builtin.rb
+++ b/app/models/group_builtin.rb
@@ -37,7 +37,7 @@ class GroupBuiltin < Group
class << self
def load_instance
return nil if self == GroupBuiltin
- instance = first(:order => 'id') || create_instance
+ instance = order('id').first || create_instance
end
def create_instance
diff --git a/app/models/group_non_member.rb b/app/models/group_non_member.rb
index 8b3dfd4aa..9f78f0b46 100644
--- a/app/models/group_non_member.rb
+++ b/app/models/group_non_member.rb
@@ -23,8 +23,4 @@ class GroupNonMember < GroupBuiltin
def builtin_type
"non_member"
end
-
- def self.instance_id
- @@instance_id ||= load_instance.id
- end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 1c1c99dec..bb45a6f58 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -31,15 +31,12 @@ class Issue < ActiveRecord::Base
has_many :journals, :as => :journalized, :dependent => :destroy
has_many :visible_journals,
+ lambda {where(["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false])},
:class_name => 'Journal',
- :as => :journalized,
- :conditions => Proc.new {
- ["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false]
- },
- :readonly => true
+ :as => :journalized
has_many :time_entries, :dependent => :destroy
- has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC"
+ has_and_belongs_to_many :changesets, lambda {order("#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC")}
has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
@@ -49,14 +46,19 @@ class Issue < ActiveRecord::Base
acts_as_customizable
acts_as_watchable
acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
- :include => [:project, :visible_journals],
# sort by id so that limited eager loading doesn't break with postgresql
- :order_column => "#{table_name}.id"
+ :order_column => "#{table_name}.id",
+ :scope => lambda { joins(:project).
+ joins("LEFT OUTER JOIN #{Journal.table_name} ON #{Journal.table_name}.journalized_type='Issue'" +
+ " AND #{Journal.table_name}.journalized_id = #{Issue.table_name}.id" +
+ " AND (#{Journal.table_name}.private_notes = #{connection.quoted_false}" +
+ " OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))") }
+
acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"},
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},
:type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }
- acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]},
+ acts_as_activity_provider :scope => preload(:project, :author, :tracker),
:author_key => :author_id
DONE_RATIO_OPTIONS = %w(issue_field issue_status)
@@ -72,19 +74,26 @@ class Issue < ActiveRecord::Base
validates :start_date, :date => true
validates :due_date, :date => true
validate :validate_issue, :validate_required_fields
+ attr_protected :id
scope :visible, lambda {|*args|
- includes(:project).where(Issue.visible_condition(args.shift || User.current, *args))
+ joins(:project).
+ references(:project).
+ where(Issue.visible_condition(args.shift || User.current, *args))
}
scope :open, lambda {|*args|
is_closed = args.size > 0 ? !args.first : false
- includes(:status).where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
+ joins(:status).
+ references(:status).
+ where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
}
scope :recently_updated, lambda { order("#{Issue.table_name}.updated_on DESC") }
scope :on_active_project, lambda {
- includes(:status, :project, :tracker).where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
+ joins(:project).
+ references(:project).
+ where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
}
scope :fixed_version, lambda {|versions|
ids = [versions].flatten.compact.map {|v| v.is_a?(Version) ? v.id : v}
@@ -107,7 +116,7 @@ class Issue < ActiveRecord::Base
# Returns a SQL conditions string used to find all issues visible by the specified user
def self.visible_condition(user, options={})
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
- if user.logged?
+ if user.id && user.logged?
case role.issues_visibility
when 'all'
nil
@@ -351,6 +360,10 @@ class Issue < ActiveRecord::Base
# Do not redefine alias chain on reload (see #4838)
alias_method_chain(:assign_attributes, :project_and_tracker_first) unless method_defined?(:assign_attributes_without_project_and_tracker_first)
+ def attributes=(new_attributes)
+ assign_attributes new_attributes
+ end
+
def estimated_hours=(h)
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
end
@@ -423,7 +436,7 @@ class Issue < ActiveRecord::Base
def safe_attributes=(attrs, user=User.current)
return unless attrs.is_a?(Hash)
- attrs = attrs.dup
+ attrs = attrs.deep_dup
# Project and Tracker must be set before since new_statuses_allowed_to depends on it.
if (p = attrs.delete('project_id')) && safe_attribute?('project_id')
@@ -458,14 +471,12 @@ class Issue < ActiveRecord::Base
if attrs['custom_field_values'].present?
editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
- # TODO: use #select when ruby1.8 support is dropped
- attrs['custom_field_values'] = attrs['custom_field_values'].reject {|k, v| !editable_custom_field_ids.include?(k.to_s)}
+ attrs['custom_field_values'].select! {|k, v| editable_custom_field_ids.include?(k.to_s)}
end
if attrs['custom_fields'].present?
editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
- # TODO: use #select when ruby1.8 support is dropped
- attrs['custom_fields'] = attrs['custom_fields'].reject {|c| !editable_custom_field_ids.include?(c['id'].to_s)}
+ attrs['custom_fields'].select! {|c| editable_custom_field_ids.include?(c['id'].to_s)}
end
# mass-assignment security bypass
@@ -733,7 +744,7 @@ class Issue < ActiveRecord::Base
def assignable_versions
return @assignable_versions if @assignable_versions
- versions = project.shared_versions.open.all
+ versions = project.shared_versions.open.to_a
if fixed_version
if fixed_version_id_changed?
# nothing to do
@@ -879,10 +890,14 @@ class Issue < ActiveRecord::Base
if issues.any?
issue_ids = issues.map(&:id)
# Relations with issue_from in given issues and visible issue_to
- relations_from = IssueRelation.includes(:issue_to => [:status, :project]).where(visible_condition(user)).where(:issue_from_id => issue_ids).all
+ relations_from = IssueRelation.joins(:issue_to => :project).
+ references(:issue_to => :project).
+ where(visible_condition(user)).where(:issue_from_id => issue_ids).to_a
# Relations with issue_to in given issues and visible issue_from
- relations_to = IssueRelation.includes(:issue_from => [:status, :project]).where(visible_condition(user)).where(:issue_to_id => issue_ids).all
-
+ relations_to = IssueRelation.joins(:issue_from => :project).
+ references(:issue_from => :project).
+ where(visible_condition(user)).
+ where(:issue_to_id => issue_ids).to_a
issues.each do |issue|
relations =
relations_from.select {|relation| relation.issue_from_id == issue.id} +
@@ -1121,6 +1136,7 @@ class Issue < ActiveRecord::Base
def parent_issue_id=(arg)
s = arg.to_s.strip.presence
if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1]))
+ @parent_issue.id
@invalid_parent_issue_id = nil
elsif s.blank?
@parent_issue = nil
@@ -1349,7 +1365,7 @@ class Issue < ActiveRecord::Base
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id)
cond = ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]
self.class.base_class.select('id').lock(true).where(cond)
- offset = right_most_bound + 1 - lft
+ offset = rdm_right_most_bound + 1 - lft
Issue.where(cond).
update_all(["root_id = ?, lft = lft + ?, rgt = rgt + ?", root_id, offset, offset])
end
@@ -1367,6 +1383,14 @@ class Issue < ActiveRecord::Base
recalculate_attributes_for(former_parent_id) if former_parent_id
end
+ def rdm_right_most_bound
+ right_most_node =
+ self.class.base_class.unscoped.
+ order("#{quoted_right_column_full_name} desc").limit(1).lock(true).first
+ right_most_node ? (right_most_node[right_column_name] || 0 ) : 0
+ end
+ private :rdm_right_most_bound
+
def update_parent_attributes
recalculate_attributes_for(parent_id) if parent_id
end
@@ -1395,7 +1419,7 @@ class Issue < ActiveRecord::Base
end
done = p.leaves.joins(:status).
sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " +
- "* (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
+ "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
progress = done / (average * leaves_count)
p.done_ratio = progress.round
end
@@ -1415,7 +1439,8 @@ class Issue < ActiveRecord::Base
def self.update_versions(conditions=nil)
# Only need to update issues with a fixed_version from
# a different project and that is not systemwide shared
- Issue.includes(:project, :fixed_version).
+ Issue.joins(:project, :fixed_version).
+ references(:version, :fixed_version).
where("#{Issue.table_name}.fixed_version_id IS NOT NULL" +
" AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
" AND #{Version.table_name}.sharing <> 'system'").
diff --git a/app/models/issue_category.rb b/app/models/issue_category.rb
index 7bee6f234..e5e508861 100644
--- a/app/models/issue_category.rb
+++ b/app/models/issue_category.rb
@@ -24,6 +24,7 @@ class IssueCategory < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name, :scope => [:project_id]
validates_length_of :name, :maximum => 30
+ attr_protected :id
safe_attributes 'name', 'assigned_to_id'
diff --git a/app/models/issue_custom_field.rb b/app/models/issue_custom_field.rb
index a1d16333d..42695e461 100644
--- a/app/models/issue_custom_field.rb
+++ b/app/models/issue_custom_field.rb
@@ -32,7 +32,7 @@ class IssueCustomField < CustomField
sql = super
id_column ||= id
tracker_condition = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id_column})"
- project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{connection.quoted_true} AND ifa.id = #{id_column})" +
+ project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{self.class.connection.quoted_true} AND ifa.id = #{id_column})" +
" OR #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id_column})"
"((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb
index c9115100c..9ca0f3077 100644
--- a/app/models/issue_query.rb
+++ b/app/models/issue_query.rb
@@ -45,7 +45,9 @@ class IssueQuery < Query
scope :visible, lambda {|*args|
user = args.shift || User.current
base = Project.allowed_to_condition(user, :view_issues, *args)
- scope = includes(:project).where("#{table_name}.project_id IS NULL OR (#{base})")
+ scope = joins("LEFT OUTER JOIN #{Project.table_name} ON #{table_name}.project_id = #{Project.table_name}.id").
+ references(:project).
+ where("#{table_name}.project_id IS NULL OR (#{base})")
if user.admin?
scope.where("#{table_name}.visibility <> ? OR #{table_name}.user_id = ?", VISIBILITY_PRIVATE, user.id)
@@ -132,17 +134,17 @@ class IssueQuery < Query
if project
principals += project.principals.sort
unless project.leaf?
- subprojects = project.descendants.visible.all
+ subprojects = project.descendants.visible.to_a
principals += Principal.member_of(subprojects)
end
- versions = project.shared_versions.all
- categories = project.issue_categories.all
+ versions = project.shared_versions.to_a
+ categories = project.issue_categories.to_a
issue_custom_fields = project.all_issue_custom_fields
else
if all_projects.any?
principals += Principal.member_of(all_projects)
end
- versions = Version.visible.where(:sharing => 'system').all
+ versions = Version.visible.where(:sharing => 'system').to_a
issue_custom_fields = IssueCustomField.where(:is_for_all => true)
end
principals.uniq!
@@ -339,7 +341,7 @@ class IssueQuery < Query
scope = scope.preload(:author)
end
- issues = scope.all
+ issues = scope.to_a
if has_column?(:spent_hours)
Issue.load_visible_spent_hours(issues)
@@ -360,12 +362,13 @@ class IssueQuery < Query
joins(:status, :project).
where(statement).
includes(([:status, :project] + (options[:include] || [])).uniq).
+ references(([:status, :project] + (options[:include] || [])).uniq).
where(options[:conditions]).
order(order_option).
joins(joins_for_order_statement(order_option.join(','))).
limit(options[:limit]).
offset(options[:offset]).
- find_ids
+ pluck(:id)
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -380,7 +383,7 @@ class IssueQuery < Query
limit(options[:limit]).
offset(options[:offset]).
preload(:details, :user, {:issue => [:project, :author, :tracker, :status]}).
- all
+ to_a
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -392,7 +395,8 @@ class IssueQuery < Query
where(project_statement).
where(options[:conditions]).
includes(:project).
- all
+ references(:project).
+ to_a
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -411,7 +415,7 @@ class IssueQuery < Query
groups = Group.givable
operator = '!' # Override the operator since we want to find by assigned_to
else
- groups = Group.where(:id => value).all
+ groups = Group.where(:id => value).to_a
end
groups ||= []
@@ -431,7 +435,7 @@ class IssueQuery < Query
" WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))"
when "=", "!"
role_cond = value.any? ?
- "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" :
+ "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")" :
"1=0"
sw = operator == "!" ? 'NOT' : ''
@@ -443,7 +447,7 @@ class IssueQuery < Query
def sql_for_is_private_field(field, operator, value)
op = (operator == "=" ? 'IN' : 'NOT IN')
- va = value.map {|v| v == '0' ? connection.quoted_false : connection.quoted_true}.uniq.join(',')
+ va = value.map {|v| v == '0' ? self.class.connection.quoted_false : self.class.connection.quoted_true}.uniq.join(',')
"#{Issue.table_name}.is_private #{op} (#{va})"
end
@@ -462,14 +466,14 @@ class IssueQuery < Query
sql = case operator
when "*", "!*"
op = (operator == "*" ? 'IN' : 'NOT IN')
- "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}')"
+ "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}')"
when "=", "!"
op = (operator == "=" ? 'IN' : 'NOT IN')
- "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = #{value.first.to_i})"
+ "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = #{value.first.to_i})"
when "=p", "=!p", "!p"
op = (operator == "!p" ? 'NOT IN' : 'IN')
comp = (operator == "=!p" ? '<>' : '=')
- "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.project_id #{comp} #{value.first.to_i})"
+ "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.project_id #{comp} #{value.first.to_i})"
end
if relation_options[:sym] == field && !options[:reverse]
diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb
index d19ff50c5..ba0624a04 100644
--- a/app/models/issue_status.rb
+++ b/app/models/issue_status.rb
@@ -27,6 +27,7 @@ class IssueStatus < ActiveRecord::Base
validates_uniqueness_of :name
validates_length_of :name, :maximum => 30
validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true
+ attr_protected :id
scope :sorted, lambda { order("#{table_name}.position ASC") }
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
@@ -79,7 +80,7 @@ class IssueStatus < ActiveRecord::Base
includes(:new_status).
where(["role_id IN (:role_ids) AND tracker_id = :tracker_id AND (#{conditions})",
{:role_ids => roles.collect(&:id), :tracker_id => tracker.id, :true => true, :false => false}
- ]).all.
+ ]).to_a.
map(&:new_status).compact.sort
else
[]
diff --git a/app/models/journal.rb b/app/models/journal.rb
index e3de2b38a..543da42b8 100644
--- a/app/models/journal.rb
+++ b/app/models/journal.rb
@@ -24,6 +24,7 @@ class Journal < ActiveRecord::Base
belongs_to :user
has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
attr_accessor :indice
+ attr_protected :id
acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" },
:description => :notes,
@@ -34,17 +35,18 @@ class Journal < ActiveRecord::Base
acts_as_activity_provider :type => 'issues',
:author_key => :user_id,
- :find_options => {:include => [{:issue => :project}, :details, :user],
- :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" +
- " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
+ :scope => preload({:issue => :project}, :user).
+ joins("LEFT OUTER JOIN #{JournalDetail.table_name} ON #{JournalDetail.table_name}.journal_id = #{Journal.table_name}.id").
+ where("#{Journal.table_name}.journalized_type = 'Issue' AND" +
+ " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')")
before_create :split_private_notes
after_create :send_notification
scope :visible, lambda {|*args|
user = args.shift || User.current
-
- includes(:issue => :project).
+ joins(:issue => :project).
+ references(:project).
where(Issue.visible_condition(user, *args)).
where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false)
}
diff --git a/app/models/journal_detail.rb b/app/models/journal_detail.rb
index 2557ce87d..e67c19840 100644
--- a/app/models/journal_detail.rb
+++ b/app/models/journal_detail.rb
@@ -18,6 +18,7 @@
class JournalDetail < ActiveRecord::Base
belongs_to :journal
before_save :normalize_values
+ attr_protected :id
def custom_field
if property == 'cf'
diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb
index 4aaa21c98..be737931c 100644
--- a/app/models/mail_handler.rb
+++ b/app/models/mail_handler.rb
@@ -42,7 +42,7 @@ class MailHandler < ActionMailer::Base
@@handler_options[:no_notification] = (@@handler_options[:no_notification].to_s == '1')
@@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1')
- email.force_encoding('ASCII-8BIT') if email.respond_to?(:force_encoding)
+ email.force_encoding('ASCII-8BIT')
super(email)
end
@@ -417,7 +417,7 @@ class MailHandler < ActionMailer::Base
end
parts.reject! do |part|
- part.header[:content_disposition].try(:disposition_type) == 'attachment'
+ part.attachment?
end
@plain_text_body = parts.map do |p|
diff --git a/app/models/member.rb b/app/models/member.rb
index aa1d50cdf..8256d2e68 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -25,6 +25,7 @@ class Member < ActiveRecord::Base
validates_presence_of :principal, :project
validates_uniqueness_of :user_id, :scope => :project_id
validate :validate_role
+ attr_protected :id
before_destroy :set_issue_category_nil
diff --git a/app/models/member_role.rb b/app/models/member_role.rb
index 74d4c631f..038509026 100644
--- a/app/models/member_role.rb
+++ b/app/models/member_role.rb
@@ -26,6 +26,7 @@ class MemberRole < ActiveRecord::Base
validates_presence_of :role
validate :validate_role_member
+ attr_protected :id
def validate_role_member
errors.add :role_id, :invalid if role && !role.member?
diff --git a/app/models/message.rb b/app/models/message.rb
index 576be4763..028a3eb55 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -22,9 +22,10 @@ class Message < ActiveRecord::Base
acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
acts_as_attachable
belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
+ attr_protected :id
acts_as_searchable :columns => ['subject', 'content'],
- :include => {:board => :project},
+ :scope => preload(:board => :project),
:project_key => "#{Board.table_name}.project_id",
:date_column => "#{table_name}.created_on"
acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
@@ -34,7 +35,7 @@ class Message < ActiveRecord::Base
:url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
{:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})}
- acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]},
+ acts_as_activity_provider :scope => preload({:board => :project}, :author),
:author_key => :author_id
acts_as_watchable
@@ -48,7 +49,9 @@ class Message < ActiveRecord::Base
after_create :send_notification
scope :visible, lambda {|*args|
- includes(:board => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
+ joins(:board => :project).
+ references(:board => :project).
+ where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
}
safe_attributes 'subject', 'content'
diff --git a/app/models/news.rb b/app/models/news.rb
index b86e3f63d..baaa92fba 100644
--- a/app/models/news.rb
+++ b/app/models/news.rb
@@ -19,16 +19,18 @@ class News < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
- has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
+ has_many :comments, lambda {order("created_on")}, :as => :commented, :dependent => :delete_all
validates_presence_of :title, :description
validates_length_of :title, :maximum => 60
validates_length_of :summary, :maximum => 255
+ attr_protected :id
acts_as_attachable :delete_permission => :manage_news
- acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project
+ acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"],
+ :scope => preload(:project)
acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
- acts_as_activity_provider :find_options => {:include => [:project, :author]},
+ acts_as_activity_provider :scope => preload(:project, :author),
:author_key => :author_id
acts_as_watchable
@@ -36,7 +38,9 @@ class News < ActiveRecord::Base
after_create :send_notification
scope :visible, lambda {|*args|
- includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
+ joins(:project).
+ references([:author, :project]).
+ where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
}
safe_attributes 'title', 'summary', 'description'
@@ -68,7 +72,7 @@ class News < ActiveRecord::Base
# returns latest news for projects visible by user
def self.latest(user = User.current, count = 5)
- visible(user).includes([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).all
+ visible(user).joins([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).to_a
end
private
diff --git a/app/models/principal.rb b/app/models/principal.rb
index 1bbbbe88e..d10241b3f 100644
--- a/app/models/principal.rb
+++ b/app/models/principal.rb
@@ -25,11 +25,13 @@ class Principal < ActiveRecord::Base
STATUS_LOCKED = 3
has_many :members, :foreign_key => 'user_id', :dependent => :destroy
- has_many :memberships, :class_name => 'Member',
- :foreign_key => 'user_id',
- :include => [:project, :roles],
- :conditions => "#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}",
- :order => "#{Project.table_name}.name"
+ has_many :memberships,
+ lambda {preload(:project, :roles).
+ joins(:project).
+ where("#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}").
+ order("#{Project.table_name}.name")},
+ :class_name => 'Member',
+ :foreign_key => 'user_id'
has_many :projects, :through => :memberships
has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
@@ -56,8 +58,8 @@ class Principal < ActiveRecord::Base
# Principals that are members of a collection of projects
scope :member_of, lambda {|projects|
- projects = [projects] unless projects.is_a?(Array)
- if projects.empty?
+ projects = [projects] if projects.is_a?(Project)
+ if projects.blank?
where("1=0")
else
ids = projects.map(&:id)
diff --git a/app/models/project.rb b/app/models/project.rb
index 6a428b209..c2b8af134 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -28,31 +28,35 @@ class Project < ActiveRecord::Base
# Specific overridden Activities
has_many :time_entry_activities
- has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
+ has_many :members,
+ lambda { joins(:principal, :roles).
+ references(:principal, :roles).
+ where("#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}") }
has_many :memberships, :class_name => 'Member'
- has_many :member_principals, :class_name => 'Member',
- :include => :principal,
- :conditions => "#{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
-
+ has_many :member_principals,
+ lambda { joins(:principal).
+ references(:principal).
+ where("#{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}")},
+ :class_name => 'Member'
has_many :enabled_modules, :dependent => :delete_all
- has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
- has_many :issues, :dependent => :destroy, :include => [:status, :tracker]
+ has_and_belongs_to_many :trackers, lambda {order("#{Tracker.table_name}.position")}
+ has_many :issues, :dependent => :destroy
has_many :issue_changes, :through => :issues, :source => :journals
- has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
+ has_many :versions, lambda {order("#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC")}, :dependent => :destroy
has_many :time_entries, :dependent => :destroy
has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all
has_many :documents, :dependent => :destroy
- has_many :news, :dependent => :destroy, :include => :author
- has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
- has_many :boards, :dependent => :destroy, :order => "position ASC"
- has_one :repository, :conditions => ["is_default = ?", true]
+ has_many :news, lambda {includes(:author)}, :dependent => :destroy
+ has_many :issue_categories, lambda {order("#{IssueCategory.table_name}.name")}, :dependent => :delete_all
+ has_many :boards, lambda {order("position ASC")}, :dependent => :destroy
+ has_one :repository, lambda {where(["is_default = ?", true])}
has_many :repositories, :dependent => :destroy
has_many :changesets, :through => :repository
has_one :wiki, :dependent => :destroy
# Custom field for the project issues
has_and_belongs_to_many :issue_custom_fields,
+ lambda {order("#{CustomField.table_name}.position")},
:class_name => 'IssueCustomField',
- :order => "#{CustomField.table_name}.position",
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
:association_foreign_key => 'custom_field_id'
@@ -126,9 +130,9 @@ class Project < ActiveRecord::Base
if !initialized.key?('trackers') && !initialized.key?('tracker_ids')
default = Setting.default_projects_tracker_ids
if default.is_a?(Array)
- self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.all
+ self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.to_a
else
- self.trackers = Tracker.sorted.all
+ self.trackers = Tracker.sorted.to_a
end
end
end
@@ -144,7 +148,7 @@ class Project < ActiveRecord::Base
# returns latest created projects
# non public projects will be returned only if user is a member of those
def self.latest(user=nil, count=5)
- visible(user).limit(count).order("created_on DESC").all
+ visible(user).limit(count).order("created_on DESC").to_a
end
# Returns true if the project is visible to +user+ or to the current user.
@@ -212,9 +216,9 @@ class Project < ActiveRecord::Base
end
def override_roles(role)
- @override_members ||= memberships.where(:user_id => [GroupAnonymous.instance_id, GroupNonMember.instance_id]).all
- member = @override_members.detect {|m| role.anonymous? ^ (m.user_id == GroupNonMember.instance_id)}
- member ? member.roles : [role]
+ group_class = role.anonymous? ? GroupAnonymous : GroupNonMember
+ member = member_principals.where("#{Principal.table_name}.type = ?", group_class.name).first
+ member ? member.roles.to_a : [role]
end
def principals
@@ -364,7 +368,7 @@ class Project < ActiveRecord::Base
# by the current user
def allowed_parents
return @allowed_parents if @allowed_parents
- @allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).all
+ @allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).to_a
@allowed_parents = @allowed_parents - self_and_descendants
if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
@allowed_parents << nil
@@ -435,11 +439,12 @@ class Project < ActiveRecord::Base
@rolled_up_trackers ||=
Tracker.
joins(:projects).
+ references(:project).
joins("JOIN #{EnabledModule.table_name} ON #{EnabledModule.table_name}.project_id = #{Project.table_name}.id AND #{EnabledModule.table_name}.name = 'issue_tracking'").
select("DISTINCT #{Tracker.table_name}.*").
where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt).
sorted.
- all
+ to_a
end
# Closes open and locked project versions that are completed
@@ -457,7 +462,8 @@ class Project < ActiveRecord::Base
def rolled_up_versions
@rolled_up_versions ||=
Version.
- includes(:project).
+ joins(:project).
+ references(:project).
where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> ?", lft, rgt, STATUS_ARCHIVED)
end
@@ -465,13 +471,17 @@ class Project < ActiveRecord::Base
def shared_versions
if new_record?
Version.
- includes(:project).
+ joins(:project).
+ references(:project).
+ preload(:project).
where("#{Project.table_name}.status <> ? AND #{Version.table_name}.sharing = 'system'", STATUS_ARCHIVED)
else
@shared_versions ||= begin
r = root? ? self : root
Version.
- includes(:project).
+ joins(:project).
+ references(:project).
+ preload(:project).
where("#{Project.table_name}.id = #{id}" +
" OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
" #{Version.table_name}.sharing = 'system'" +
@@ -497,7 +507,7 @@ class Project < ActiveRecord::Base
# Deletes all project's members
def delete_all_members
me, mr = Member.table_name, MemberRole.table_name
- connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
+ self.class.connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
Member.delete_all(['project_id = ?', id])
end
@@ -728,7 +738,7 @@ class Project < ActiveRecord::Base
project = project.is_a?(Project) ? project : Project.find(project)
to_be_copied = %w(wiki versions issue_categories issues members queries boards)
- to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil?
+ to_be_copied = to_be_copied & Array.wrap(options[:only]) unless options[:only].nil?
Project.transaction do
if save
@@ -740,6 +750,7 @@ class Project < ActiveRecord::Base
save
end
end
+ true
end
# Returns a new unsaved Project instance with attributes copied from +project+
@@ -958,11 +969,10 @@ class Project < ActiveRecord::Base
def copy_queries(project)
project.queries.each do |query|
new_query = IssueQuery.new
- new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria", "user_id", "type")
+ new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
new_query.sort_criteria = query.sort_criteria if query.sort_criteria
new_query.project = self
new_query.user_id = query.user_id
- new_query.role_ids = query.role_ids if query.visibility == IssueQuery::VISIBILITY_ROLES
self.queries << new_query
end
end
diff --git a/app/models/query.rb b/app/models/query.rb
index 9ef002c6e..a4d34d1e4 100644
--- a/app/models/query.rb
+++ b/app/models/query.rb
@@ -288,7 +288,7 @@ class Query < ActiveRecord::Base
end
def trackers
- @trackers ||= project.nil? ? Tracker.sorted.all : project.rolled_up_trackers
+ @trackers ||= project.nil? ? Tracker.sorted.to_a : project.rolled_up_trackers
end
# Returns a hash of localized labels for all filter operators
@@ -306,7 +306,7 @@ class Query < ActiveRecord::Base
end
def all_projects
- @all_projects ||= Project.visible.all
+ @all_projects ||= Project.visible.to_a
end
def all_projects_values
@@ -655,7 +655,7 @@ class Query < ActiveRecord::Base
sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}"
end
else
- sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
+ sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")"
end
else
# IN an empty set
@@ -663,7 +663,7 @@ class Query < ActiveRecord::Base
end
when "!"
if value.any?
- sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
+ sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + "))"
else
# NOT IN an empty set
sql = "1=1"
@@ -705,9 +705,9 @@ class Query < ActiveRecord::Base
end
end
when "o"
- sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id"
+ sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{self.class.connection.quoted_false})" if field == "status_id"
when "c"
- sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id"
+ sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{self.class.connection.quoted_true})" if field == "status_id"
when "><t-"
# between today - n days and today
sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
@@ -769,9 +769,9 @@ class Query < ActiveRecord::Base
date = Date.today
sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year)
when "~"
- sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
+ sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{self.class.connection.quote_string(value.first.to_s.downcase)}%'"
when "!~"
- sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
+ sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{self.class.connection.quote_string(value.first.to_s.downcase)}%'"
else
raise "Unknown query operator #{operator}"
end
@@ -834,7 +834,7 @@ class Query < ActiveRecord::Base
if self.class.default_timezone == :utc
from = from.utc
end
- s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from)])
+ s << ("#{table}.#{field} > '%s'" % [self.class.connection.quoted_date(from)])
end
if to
if to.is_a?(Date)
@@ -843,7 +843,7 @@ class Query < ActiveRecord::Base
if self.class.default_timezone == :utc
to = to.utc
end
- s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to)])
+ s << ("#{table}.#{field} <= '%s'" % [self.class.connection.quoted_date(to)])
end
s.join(' AND ')
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 25b0e1da8..1cab86bd1 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -25,7 +25,7 @@ class Repository < ActiveRecord::Base
IDENTIFIER_MAX_LENGTH = 255
belongs_to :project
- has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
+ has_many :changesets, lambda{order("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC")}
has_many :filechanges, :class_name => 'Change', :through => :changesets
serialize :extra_info
@@ -45,6 +45,7 @@ class Repository < ActiveRecord::Base
validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
# Checks if the SCM is enabled when creating a repository
validate :repo_create_validation, :on => :create
+ attr_protected :id
safe_attributes 'identifier',
'login',
@@ -264,7 +265,7 @@ class Repository < ActiveRecord::Base
reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
limit(limit).
preload(:user).
- all
+ to_a
else
filechanges.
where("path = ?", path.with_leading_slash).
@@ -313,7 +314,8 @@ class Repository < ActiveRecord::Base
return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
user = nil
- c = changesets.where(:committer => committer).includes(:user).first
+ c = changesets.where(:committer => committer).
+ includes(:user).references(:user).first
if c && c.user
user = c.user
elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
@@ -484,10 +486,10 @@ class Repository < ActiveRecord::Base
ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
- connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
- connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
- connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
- connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
+ self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
+ self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
+ self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
+ self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
clear_extra_info_of_changesets
end
diff --git a/app/models/repository/cvs.rb b/app/models/repository/cvs.rb
index 09d79c4fb..abc408304 100644
--- a/app/models/repository/cvs.rb
+++ b/app/models/repository/cvs.rb
@@ -199,7 +199,7 @@ class Repository::Cvs < Repository
# Need to retrieve existing revision numbers to sort them as integers
sql = "SELECT revision FROM #{Changeset.table_name} "
sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
- @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
+ @current_revision_number ||= (self.class.connection.select_values(sql).collect(&:to_i).max || 0)
@current_revision_number += 1
end
end
diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb
index c51a7e58a..978944efc 100644
--- a/app/models/repository/git.rb
+++ b/app/models/repository/git.rb
@@ -241,7 +241,7 @@ class Repository::Git < Repository
def latest_changesets(path,rev,limit=10)
revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
return [] if revisions.nil? || revisions.empty?
- changesets.where(:scmid => revisions.map {|c| c.scmid}).all
+ changesets.where(:scmid => revisions.map {|c| c.scmid}).to_a
end
def clear_extra_info_of_changesets
diff --git a/app/models/repository/mercurial.rb b/app/models/repository/mercurial.rb
index abe1dfb70..81dd24d00 100644
--- a/app/models/repository/mercurial.rb
+++ b/app/models/repository/mercurial.rb
@@ -20,7 +20,7 @@ require 'redmine/scm/adapters/mercurial_adapter'
class Repository::Mercurial < Repository
# sort changesets by revision number
has_many :changesets,
- :order => "#{Changeset.table_name}.id DESC",
+ lambda {order("#{Changeset.table_name}.id DESC")},
:foreign_key => 'repository_id'
attr_protected :root_url
@@ -117,9 +117,10 @@ class Repository::Mercurial < Repository
changesets.
includes(:user).
where(latest_changesets_cond(path, rev, limit)).
+ references(:user).
limit(limit).
order("#{Changeset.table_name}.id DESC").
- all
+ to_a
end
def is_short_id_in_db?
diff --git a/app/models/repository/subversion.rb b/app/models/repository/subversion.rb
index 532c1f3a2..1659b77f8 100644
--- a/app/models/repository/subversion.rb
+++ b/app/models/repository/subversion.rb
@@ -42,7 +42,7 @@ class Repository::Subversion < Repository
revisions = scm.revisions(path, rev, nil, :limit => limit)
if revisions
identifiers = revisions.collect(&:identifier).compact
- changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).all
+ changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).to_a
else
[]
end
diff --git a/app/models/role.rb b/app/models/role.rb
index 10977612d..efd9a334d 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -166,7 +166,7 @@ class Role < ActiveRecord::Base
# Find all the roles that can be given to a project member
def self.find_all_givable
- Role.givable.all
+ Role.givable.to_a
end
# Return the builtin 'non member' role. If the role doesn't exist,
diff --git a/app/models/setting.rb b/app/models/setting.rb
index 532e9d44d..3881f90f1 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -86,6 +86,7 @@ class Setting < ActiveRecord::Base
validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
(s = @@available_settings[setting.name]) && s['format'] == 'int'
}
+ attr_protected :id
# Hash used to cache setting values
@cached_settings = {}
@@ -142,6 +143,7 @@ END_SRC
def self.set_from_params(name, params)
params = params.dup
params.delete_if {|v| v.blank? } if params.is_a?(Array)
+ params.symbolize_keys! if params.is_a?(Hash)
m = "#{name}_from_params"
if respond_to? m
diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb
index 662070840..8738668cc 100644
--- a/app/models/time_entry.rb
+++ b/app/models/time_entry.rb
@@ -35,7 +35,7 @@ class TimeEntry < ActiveRecord::Base
acts_as_activity_provider :timestamp => "#{table_name}.created_on",
:author_key => :user_id,
- :find_options => {:include => :project}
+ :scope => preload(:project)
validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
validates_numericality_of :hours, :allow_nil => true, :message => :invalid
@@ -45,13 +45,19 @@ class TimeEntry < ActiveRecord::Base
validate :validate_time_entry
scope :visible, lambda {|*args|
- includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
+ joins(:project).
+ references(:project).
+ where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
}
scope :on_issue, lambda {|issue|
- includes(:issue).where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
+ joins(:issue).
+ references(:issue).
+ where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
}
scope :on_project, lambda {|project, include_subprojects|
- includes(:project).where(project.project_condition(include_subprojects))
+ joins(:project).
+ references(:project).
+ where(project.project_condition(include_subprojects))
}
scope :spent_between, lambda {|from, to|
if from && to
diff --git a/app/models/time_entry_query.rb b/app/models/time_entry_query.rb
index bd2eef398..05c39f55e 100644
--- a/app/models/time_entry_query.rb
+++ b/app/models/time_entry_query.rb
@@ -42,7 +42,7 @@ class TimeEntryQuery < Query
if project
principals += project.principals.sort
unless project.leaf?
- subprojects = project.descendants.visible.all
+ subprojects = project.descendants.visible.to_a
if subprojects.any?
add_available_filter "subproject_id",
:type => :list_subprojects,
@@ -109,7 +109,8 @@ class TimeEntryQuery < Query
where(statement).
order(order_option).
joins(joins_for_order_statement(order_option.join(','))).
- includes(:activity)
+ includes(:activity).
+ references(:activity)
end
def sql_for_activity_id_field(field, operator, value)
diff --git a/app/models/token.rb b/app/models/token.rb
index b1d2d2905..0f3751030 100644
--- a/app/models/token.rb
+++ b/app/models/token.rb
@@ -18,6 +18,7 @@
class Token < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :value
+ attr_protected :id
before_create :delete_previous_tokens, :generate_new_token
diff --git a/app/models/tracker.rb b/app/models/tracker.rb
index 20ba84527..b4f22c811 100644
--- a/app/models/tracker.rb
+++ b/app/models/tracker.rb
@@ -63,7 +63,7 @@ class Tracker < ActiveRecord::Base
connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{WorkflowTransition.table_name} WHERE tracker_id = #{id} AND type = 'WorkflowTransition'").
flatten.
uniq
- @issue_statuses = IssueStatus.where(:id => ids).all.sort
+ @issue_statuses = IssueStatus.where(:id => ids).to_a.sort
end
def disabled_core_fields
@@ -92,7 +92,7 @@ class Tracker < ActiveRecord::Base
# Returns the fields that are disabled for all the given trackers
def self.disabled_core_fields(trackers)
if trackers.present?
- trackers.uniq.map(&:disabled_core_fields).reduce(:&)
+ trackers.map(&:disabled_core_fields).reduce(:&)
else
[]
end
diff --git a/app/models/user.rb b/app/models/user.rb
index d8590f47c..d86627e85 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -79,8 +79,8 @@ class User < Principal
:after_remove => Proc.new {|user, group| group.user_removed(user)}
has_many :changesets, :dependent => :nullify
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
- has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
- has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
+ has_one :rss_token, lambda {where "action='feeds'"}, :class_name => 'Token'
+ has_one :api_token, lambda {where "action='api'"}, :class_name => 'Token'
belongs_to :auth_source
scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
@@ -105,9 +105,13 @@ class User < Principal
validates_length_of :firstname, :lastname, :maximum => 30
validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
- validates_confirmation_of :password, :allow_nil => true
validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
validate :validate_password_length
+ validate do
+ if password_confirmation && password != password_confirmation
+ errors.add(:password, :confirmation)
+ end
+ end
before_create :set_mail_notification
before_save :generate_password_if_needed, :update_hashed_password
@@ -151,6 +155,15 @@ class User < Principal
write_attribute(:mail, arg.to_s.strip)
end
+ def self.find_or_initialize_by_identity_url(url)
+ user = where(:identity_url => url).first
+ unless user
+ user = User.new
+ user.identity_url = url
+ end
+ user
+ end
+
def identity_url=(url)
if url.blank?
write_attribute(:identity_url, '')
@@ -496,10 +509,12 @@ class User < Principal
hash = Hash.new([])
- members = Member.joins(:project).
+ group_class = anonymous? ? GroupAnonymous : GroupNonMember
+ members = Member.joins(:project, :principal).
where("#{Project.table_name}.status <> 9").
- where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Member.table_name}.user_id = ?)", self.id, true, Group.builtin_id(self)).
- preload(:project, :roles)
+ where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Principal.table_name}.type = ?)", self.id, true, group_class.name).
+ preload(:project, :roles).
+ to_a
members.reject! {|member| member.user_id != id && project_ids.include?(member.project_id)}
members.each do |member|
@@ -558,6 +573,8 @@ class User < Principal
# Authorize if user is authorized on every element of the array
context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
end
+ elsif context
+ raise ArgumentError.new("#allowed_to? context argument must be a Project, an Array of projects or nil")
elsif options[:global]
# Admin users are always authorized
return true if admin?
@@ -710,17 +727,17 @@ class User < Principal
return if self.id.nil?
substitute = User.anonymous
- Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
+ Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
Comment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
Issue.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
Issue.where(['assigned_to_id = ?', id]).update_all('assigned_to_id = NULL')
- Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
+ Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
JournalDetail.
where(["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]).
update_all(['old_value = ?', substitute.id.to_s])
JournalDetail.
where(["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]).
- update_all(['value = ?', substitute.id.to_s])
+ update_all(['value = ?', substitute.id.to_s])
Message.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
News.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
# Remove private queries and keep public ones
diff --git a/app/models/version.rb b/app/models/version.rb
index 1d06360ef..45c7c25a6 100644
--- a/app/models/version.rb
+++ b/app/models/version.rb
@@ -33,11 +33,14 @@ class Version < ActiveRecord::Base
validates :effective_date, :date => true
validates_inclusion_of :status, :in => VERSION_STATUSES
validates_inclusion_of :sharing, :in => VERSION_SHARINGS
+ attr_protected :id
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
scope :open, lambda { where(:status => 'open') }
scope :visible, lambda {|*args|
- includes(:project).where(Project.allowed_to_condition(args.first || User.current, :view_issues))
+ joins(:project).
+ references(:project).
+ where(Project.allowed_to_condition(args.first || User.current, :view_issues))
}
safe_attributes 'name',
@@ -230,11 +233,6 @@ class Version < ActiveRecord::Base
end
end
- # Returns true if the version is shared, otherwise false
- def shared?
- sharing != 'none'
- end
-
private
def load_issue_counts
diff --git a/app/models/watcher.rb b/app/models/watcher.rb
index 1f42de86f..9981bea1c 100644
--- a/app/models/watcher.rb
+++ b/app/models/watcher.rb
@@ -22,6 +22,7 @@ class Watcher < ActiveRecord::Base
validates_presence_of :user
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
validate :validate_user
+ attr_protected :id
# Returns true if at least one object among objects is watched by user
def self.any_watched?(objects, user)
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index 45a22fda1..b1ce29743 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -18,13 +18,14 @@
class Wiki < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project
- has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'
+ has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
acts_as_watchable
validates_presence_of :start_page
validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
+ attr_protected :id
safe_attributes 'start_page'
diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb
index 415ba9aca..3eac92688 100644
--- a/app/models/wiki_content.rb
+++ b/app/models/wiki_content.rb
@@ -23,6 +23,7 @@ class WikiContent < ActiveRecord::Base
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :text
validates_length_of :comments, :maximum => 255, :allow_nil => true
+ attr_protected :id
acts_as_versioned
@@ -68,13 +69,13 @@ class WikiContent < ActiveRecord::Base
:timestamp => "#{WikiContent.versioned_table_name}.updated_on",
:author_key => "#{WikiContent.versioned_table_name}.author_id",
:permission => :view_wiki_edits,
- :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
- "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
- "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
- "#{WikiContent.versioned_table_name}.id",
- :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
- "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
- "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
+ :scope => select("#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
+ "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
+ "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
+ "#{WikiContent.versioned_table_name}.id").
+ joins("LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
+ "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
+ "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id")
after_destroy :page_update_after_destroy
@@ -104,7 +105,7 @@ class WikiContent < ActiveRecord::Base
# uncompressed data
data
end
- str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
+ str.force_encoding("UTF-8")
str
end
end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index fc56d9d6b..8aed835ad 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -33,7 +33,7 @@ class WikiPage < ActiveRecord::Base
:url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
- :include => [{:wiki => :project}, :content],
+ :scope => preload(:wiki => :project).joins(:content, {:wiki => :project}),
:permission => :view_wiki_pages,
:project_key => "#{Wiki.table_name}.project_id"
@@ -43,6 +43,7 @@ class WikiPage < ActiveRecord::Base
validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
validates_associated :content
+ attr_protected :id
validate :validate_parent_title
before_destroy :remove_redirects
@@ -180,12 +181,10 @@ class WikiPage < ActiveRecord::Base
def save_with_content(content)
ret = nil
transaction do
- self.content = content
- if new_record?
- # Rails automatically saves associated content
- ret = save
- else
- ret = save && (content.text_changed? ? content.save : true)
+ ret = save
+ if content.text_changed?
+ self.content = content
+ ret = ret && content.changed?
end
raise ActiveRecord::Rollback unless ret
end
diff --git a/app/models/wiki_redirect.rb b/app/models/wiki_redirect.rb
index 403fb5c52..166453138 100644
--- a/app/models/wiki_redirect.rb
+++ b/app/models/wiki_redirect.rb
@@ -20,4 +20,5 @@ class WikiRedirect < ActiveRecord::Base
validates_presence_of :title, :redirects_to
validates_length_of :title, :redirects_to, :maximum => 255
+ attr_protected :id
end
diff --git a/app/models/workflow_rule.rb b/app/models/workflow_rule.rb
index 829b88a32..3d1b75bd0 100644
--- a/app/models/workflow_rule.rb
+++ b/app/models/workflow_rule.rb
@@ -24,6 +24,7 @@ class WorkflowRule < ActiveRecord::Base
belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'
validates_presence_of :role, :tracker, :old_status
+ attr_protected :id
# Copies workflows from source to targets
def self.copy(source_tracker, source_role, target_trackers, target_roles)
@@ -34,7 +35,7 @@ class WorkflowRule < ActiveRecord::Base
target_trackers = [target_trackers].flatten.compact
target_roles = [target_roles].flatten.compact
- target_trackers = Tracker.sorted.all if target_trackers.empty?
+ target_trackers = Tracker.sorted.to_a if target_trackers.empty?
target_roles = Role.all if target_roles.empty?
target_trackers.each do |target_tracker|
diff --git a/app/models/workflow_transition.rb b/app/models/workflow_transition.rb
index 6b04d5983..e88769aa7 100644
--- a/app/models/workflow_transition.rb
+++ b/app/models/workflow_transition.rb
@@ -40,7 +40,7 @@ class WorkflowTransition < WorkflowRule
roles = Array.wrap roles
transaction do
- records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).all
+ records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).to_a
transitions.each do |old_status_id, transitions_by_new_status|
transitions_by_new_status.each do |new_status_id, transition_by_rule|