diff options
Diffstat (limited to 'app')
98 files changed, 434 insertions, 328 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index c2d464d42..b0e5ce6fa 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -34,7 +34,7 @@ class AdminController < ApplicationController scope = Project.status(@status).order('lft') scope = scope.like(params[:name]) if params[:name].present? - @projects = scope.all + @projects = scope.to_a render :action => "projects", :layout => false if request.xhr? end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e8f3565ee..7fedd44ff 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -496,7 +496,7 @@ class ApplicationController < ActionController::Base end def render_feed(items, options={}) - @items = items || [] + @items = (items || []).to_a @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items = @items.slice(0, Setting.feeds_limit.to_i) @title = options[:title] || Setting.app_title diff --git a/app/controllers/auto_completes_controller.rb b/app/controllers/auto_completes_controller.rb index a48afdf90..991f0be16 100644 --- a/app/controllers/auto_completes_controller.rb +++ b/app/controllers/auto_completes_controller.rb @@ -26,7 +26,7 @@ class AutoCompletesController < ApplicationController if q.match(/\A#?(\d+)\z/) @issues << scope.find_by_id($1.to_i) end - @issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all + @issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).to_a @issues.compact! end render :layout => false diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index 1f1d47342..04bdb56c0 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -25,7 +25,7 @@ class BoardsController < ApplicationController helper :watchers def index - @boards = @project.boards.includes(:project, :last_message => :author).all + @boards = @project.boards.preload(:project, :last_message => :author).to_a # show the board if there is only one if @boards.size == 1 @board = @boards.first @@ -45,12 +45,13 @@ class BoardsController < ApplicationController @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] @topics = @board.topics. reorder("#{Message.table_name}.sticky DESC"). - includes(:last_reply). + joins("LEFT OUTER JOIN #{Message.table_name} last_replies_messages ON last_replies_messages.id = #{Message.table_name}.last_reply_id"). + references(:last_reply). limit(@topic_pages.per_page). offset(@topic_pages.offset). order(sort_clause). preload(:author, {:last_reply => :author}). - all + to_a @message = Message.new(:board => @board) render :action => 'show', :layout => !request.xhr? } @@ -59,7 +60,7 @@ class BoardsController < ApplicationController reorder('created_on DESC'). includes(:author, :board). limit(Setting.feeds_limit.to_i). - all + to_a render_feed(@messages, :title => "#{@project}: #{@board}") } end diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index 43cfc2530..47065f934 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -27,7 +27,7 @@ class DocumentsController < ApplicationController def index @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' - documents = @project.documents.includes(:attachments, :category).all + documents = @project.documents.includes(:attachments, :category).to_a case @sort_by when 'date' @grouped = documents.group_by {|d| d.updated_on.to_date } @@ -43,7 +43,7 @@ class DocumentsController < ApplicationController end def show - @attachments = @document.attachments.all + @attachments = @document.attachments.to_a end def new @@ -69,7 +69,7 @@ class DocumentsController < ApplicationController def update @document.safe_attributes = params[:document] - if request.put? and @document.save + if @document.save flash[:notice] = l(:notice_successful_update) redirect_to document_path(@document) else diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb index 65a503974..d8d9141bb 100644 --- a/app/controllers/enumerations_controller.rb +++ b/app/controllers/enumerations_controller.rb @@ -32,7 +32,7 @@ class EnumerationsController < ApplicationController format.api { @klass = Enumeration.get_subclass(params[:type]) if @klass - @enumerations = @klass.shared.sorted.all + @enumerations = @klass.shared.sorted.to_a else render_404 end @@ -56,7 +56,7 @@ class EnumerationsController < ApplicationController end def update - if request.put? && @enumeration.update_attributes(params[:enumeration]) + if @enumeration.update_attributes(params[:enumeration]) flash[:notice] = l(:notice_successful_update) redirect_to enumerations_path else @@ -75,7 +75,7 @@ class EnumerationsController < ApplicationController redirect_to enumerations_path return end - @enumerations = @enumeration.class.system.all - [@enumeration] + @enumerations = @enumeration.class.system.to_a - [@enumeration] end private diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index 6ba5c110c..f3eb6719f 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -31,8 +31,10 @@ class FilesController < ApplicationController 'size' => "#{Attachment.table_name}.filesize", 'downloads' => "#{Attachment.table_name}.downloads" - @containers = [ Project.includes(:attachments).reorder(sort_clause).find(@project.id)] - @containers += @project.versions.includes(:attachments).reorder(sort_clause).all.sort.reverse + @containers = [Project.includes(:attachments). + references(:attachments).reorder(sort_clause).find(@project.id)] + @containers += @project.versions.includes(:attachments). + references(:attachments).reorder(sort_clause).to_a.sort.reverse render :layout => !request.xhr? end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 555fc61df..45ed4c4e1 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -27,13 +27,13 @@ class GroupsController < ApplicationController def index respond_to do |format| format.html { - @groups = Group.sorted.all + @groups = Group.sorted.to_a @user_count_by_group_id = user_count_by_group_id } format.api { scope = Group.sorted scope = scope.givable unless params[:builtin] == '1' - @groups = scope.all + @groups = scope.to_a } end end @@ -95,7 +95,7 @@ class GroupsController < ApplicationController end def add_users - @users = User.where(:id => (params[:user_id] || params[:user_ids])).all + @users = User.where(:id => (params[:user_id] || params[:user_ids])).to_a @group.users << @users if request.post? respond_to do |format| format.html { redirect_to edit_group_path(@group, :tab => 'users') } diff --git a/app/controllers/issue_categories_controller.rb b/app/controllers/issue_categories_controller.rb index 6a956904a..3c73510ee 100644 --- a/app/controllers/issue_categories_controller.rb +++ b/app/controllers/issue_categories_controller.rb @@ -27,7 +27,7 @@ class IssueCategoriesController < ApplicationController def index respond_to do |format| format.html { redirect_to_settings_in_projects } - format.api { @categories = @project.issue_categories.all } + format.api { @categories = @project.issue_categories.to_a } end end diff --git a/app/controllers/issue_statuses_controller.rb b/app/controllers/issue_statuses_controller.rb index d305dedd7..a6b72f329 100644 --- a/app/controllers/issue_statuses_controller.rb +++ b/app/controllers/issue_statuses_controller.rb @@ -29,7 +29,7 @@ class IssueStatusesController < ApplicationController render :action => "index", :layout => false if request.xhr? } format.api { - @issue_statuses = IssueStatus.order('position').all + @issue_statuses = IssueStatus.order('position').to_a } end end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index de346c576..5623c3bfa 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -104,15 +104,16 @@ class IssuesController < ApplicationController end def show - @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all + @journals = @issue.journals.includes(:user, :details). + references(:user, :details). + reorder("#{Journal.table_name}.id ASC").to_a @journals.each_with_index {|j,i| j.indice = i+1} @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) Journal.preload_journals_details_custom_fields(@journals) - # TODO: use #select! when ruby1.8 support is dropped - @journals.reject! {|journal| !journal.notes? && journal.visible_details.empty?} + @journals.select! {|journal| journal.notes? || journal.visible_details.any?} @journals.reverse! if User.current.wants_comments_in_reverse_order? - @changesets = @issue.changesets.visible.all + @changesets = @issue.changesets.visible.to_a @changesets.reverse! if User.current.wants_comments_in_reverse_order? @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } @@ -189,7 +190,7 @@ class IssuesController < ApplicationController rescue ActiveRecord::StaleObjectError @conflict = true if params[:last_journal_id] - @conflict_journals = @issue.journals_after(params[:last_journal_id]).all + @conflict_journals = @issue.journals_after(params[:last_journal_id]).to_a @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) end end @@ -301,7 +302,7 @@ class IssuesController < ApplicationController else @saved_issues = @issues @unsaved_issues = unsaved_issues - @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).all + @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).to_a bulk_edit render :action => 'bulk_edit' end @@ -375,7 +376,9 @@ class IssuesController < ApplicationController def update_issue_from_params @edit_allowed = User.current.allowed_to?(:edit_issues, @project) @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) - @time_entry.attributes = params[:time_entry] + if params[:time_entry] + @time_entry.attributes = params[:time_entry] + end @issue.init_journal(User.current) @@ -422,7 +425,9 @@ class IssuesController < ApplicationController @issue.project = @project @issue.author ||= User.current # Tracker must be set before custom field values - @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) + tracker_id = (params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] + tracker = tracker_id.present? ? @project.trackers.find(tracker_id) : @project.trackers.first + @issue.tracker ||= tracker if @issue.tracker.nil? render_error l(:error_no_tracker_in_project) return false diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index fe1c01907..940a7b5e1 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -34,7 +34,6 @@ class JournalsController < ApplicationController retrieve_query sort_init 'id', 'desc' sort_update(@query.sortable_columns) - if @query.valid? @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", :limit => 25) diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index aca136754..ca5002af8 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -32,7 +32,7 @@ class MembersController < ApplicationController order("#{Member.table_name}.id"). limit(@limit). offset(@offset). - all + to_a respond_to do |format| format.html { head 406 } format.api @@ -63,7 +63,10 @@ class MembersController < ApplicationController respond_to do |format| format.html { redirect_to_settings_in_projects } - format.js { @members = members } + format.js { + @members = members + @member = Member.new + } format.api { @member = members.first if @member.valid? diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 0eb9f0bef..aa0788a05 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -43,10 +43,10 @@ class MessagesController < ApplicationController @reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page @replies = @topic.children. includes(:author, :attachments, {:board => :project}). - reorder("#{Message.table_name}.created_on ASC"). + reorder("#{Message.table_name}.created_on ASC, #{Message.table_name}.id ASC"). limit(@reply_pages.per_page). offset(@reply_pages.offset). - all + to_a @reply = Message.new(:subject => "RE: #{@message.subject}") render :action => "show", :layout => false if request.xhr? diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index 714b23857..4fd18bab0 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -53,8 +53,8 @@ class MyController < ApplicationController @user = User.current @pref = @user.pref if request.post? - @user.safe_attributes = params[:user] - @user.pref.attributes = params[:pref] + @user.safe_attributes = params[:user] if params[:user] + @user.pref.attributes = params[:pref] if params[:pref] if @user.save @user.pref.save set_language_if_valid @user.language diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb index ffe662921..50c0489f4 100644 --- a/app/controllers/news_controller.rb +++ b/app/controllers/news_controller.rb @@ -46,7 +46,7 @@ class NewsController < ApplicationController order("#{News.table_name}.created_on DESC"). limit(@limit). offset(@offset). - all + to_a respond_to do |format| format.html { @news = News.new # for adding news inline diff --git a/app/controllers/project_enumerations_controller.rb b/app/controllers/project_enumerations_controller.rb index 2475dbf65..df4fcbf23 100644 --- a/app/controllers/project_enumerations_controller.rb +++ b/app/controllers/project_enumerations_controller.rb @@ -20,7 +20,7 @@ class ProjectEnumerationsController < ApplicationController before_filter :authorize def update - if request.put? && params[:enumerations] + if params[:enumerations] Project.transaction do params[:enumerations].each do |id, activity| @project.update_or_create_time_entry_activity(id, activity) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 1225f2f01..0a6b487a8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -53,30 +53,30 @@ class ProjectsController < ApplicationController unless params[:closed] scope = scope.active end - @projects = scope.visible.order('lft').all + @projects = scope.visible.order('lft').to_a } format.api { @offset, @limit = api_offset_and_limit @project_count = Project.visible.count - @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all + @projects = Project.visible.offset(@offset).limit(@limit).order('lft').to_a } format.atom { - projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all + projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).to_a render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") } end end def new - @issue_custom_fields = IssueCustomField.sorted.all - @trackers = Tracker.sorted.all + @issue_custom_fields = IssueCustomField.sorted.to_a + @trackers = Tracker.sorted.to_a @project = Project.new @project.safe_attributes = params[:project] end def create - @issue_custom_fields = IssueCustomField.sorted.all - @trackers = Tracker.sorted.all + @issue_custom_fields = IssueCustomField.sorted.to_a + @trackers = Tracker.sorted.to_a @project = Project.new @project.safe_attributes = params[:project] @@ -109,8 +109,8 @@ class ProjectsController < ApplicationController end def copy - @issue_custom_fields = IssueCustomField.sorted.all - @trackers = Tracker.sorted.all + @issue_custom_fields = IssueCustomField.sorted.to_a + @trackers = Tracker.sorted.to_a @source_project = Project.find(params[:id]) if request.get? @project = Project.copy_from(@source_project) @@ -145,8 +145,8 @@ class ProjectsController < ApplicationController end @users_by_role = @project.users_by_role - @subprojects = @project.children.visible.all - @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all + @subprojects = @project.children.visible.to_a + @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").to_a @trackers = @project.rolled_up_trackers cond = @project.project_condition(Setting.display_subprojects_issues?) @@ -167,10 +167,10 @@ class ProjectsController < ApplicationController end def settings - @issue_custom_fields = IssueCustomField.sorted.all + @issue_custom_fields = IssueCustomField.sorted.to_a @issue_category ||= IssueCategory.new @member ||= @project.members.new - @trackers = Tracker.sorted.all + @trackers = Tracker.sorted.to_a @wiki ||= @project.wiki end diff --git a/app/controllers/queries_controller.rb b/app/controllers/queries_controller.rb index 049e3534b..22ec9e929 100644 --- a/app/controllers/queries_controller.rb +++ b/app/controllers/queries_controller.rb @@ -37,8 +37,9 @@ class QueriesController < ApplicationController order("#{Query.table_name}.name"). limit(@limit). offset(@offset). - all + to_a respond_to do |format| + format.html {render_error :status => 406} format.api end end diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 00c94a106..43dac3673 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -90,6 +90,6 @@ class ReportsController < ApplicationController private def find_issue_statuses - @statuses = IssueStatus.sorted.all + @statuses = IssueStatus.sorted.to_a end end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 59afc5529..7eb72865b 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -69,7 +69,7 @@ class RepositoriesController < ApplicationController @repository.merge_extra_info(attrs[:attrs_extra]) end @repository.project = @project - if request.put? && @repository.save + if @repository.save redirect_to settings_project_path(@project, :tab => 'repositories') else render :action => 'edit' @@ -94,7 +94,7 @@ class RepositoriesController < ApplicationController @committers = @repository.committers @users = @project.users additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) - @users += User.where(:id => additional_user_ids).all unless additional_user_ids.empty? + @users += User.where(:id => additional_user_ids).to_a unless additional_user_ids.empty? @users.compact! @users.sort! if request.post? && params[:committers].is_a?(Hash) @@ -145,7 +145,7 @@ class RepositoriesController < ApplicationController limit(@changeset_pages.per_page). offset(@changeset_pages.offset). includes(:user, :repository, :parents). - all + to_a respond_to do |format| format.html { render :layout => false if request.xhr? } diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index 8a976779e..a74d8bb91 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -30,7 +30,7 @@ class RolesController < ApplicationController render :action => "index", :layout => false if request.xhr? } format.api { - @roles = Role.givable.all + @roles = Role.givable.to_a } end end @@ -47,7 +47,7 @@ class RolesController < ApplicationController if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy]) @role.copy_from(@copy_from) end - @roles = Role.sorted.all + @roles = Role.sorted.to_a end def create @@ -60,7 +60,7 @@ class RolesController < ApplicationController flash[:notice] = l(:notice_successful_create) redirect_to roles_path else - @roles = Role.sorted.all + @roles = Role.sorted.to_a render :action => 'new' end end @@ -69,7 +69,7 @@ class RolesController < ApplicationController end def update - if request.put? and @role.update_attributes(params[:role]) + if @role.update_attributes(params[:role]) flash[:notice] = l(:notice_successful_update) redirect_to roles_path else @@ -86,7 +86,7 @@ class RolesController < ApplicationController end def permissions - @roles = Role.sorted.all + @roles = Role.sorted.to_a @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } if request.post? @roles.each do |role| diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index afc756677..ec8b4812c 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -31,7 +31,7 @@ class SearchController < ApplicationController when 'my_projects' User.current.memberships.collect(&:project) when 'subprojects' - @project ? (@project.self_and_descendants.active.all) : nil + @project ? (@project.self_and_descendants.active.to_a) : nil else @project end diff --git a/app/controllers/sys_controller.rb b/app/controllers/sys_controller.rb index d8ef783eb..0b62b420c 100644 --- a/app/controllers/sys_controller.rb +++ b/app/controllers/sys_controller.rb @@ -19,7 +19,8 @@ class SysController < ActionController::Base before_filter :check_enabled def projects - p = Project.active.has_module(:repository).order("#{Project.table_name}.identifier").preload(:repository).all + p = Project.active.has_module(:repository). + order("#{Project.table_name}.identifier").preload(:repository).to_a # extra_info attribute from repository breaks activeresource client render :xml => p.to_xml( :only => [:id, :identifier, :name, :is_public, :status], @@ -56,7 +57,7 @@ class SysController < ActionController::Base raise ActiveRecord::RecordNotFound unless project projects << project else - projects = scope.all + projects = scope.to_a end projects.each do |project| project.repositories.each do |repository| diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb index 13923b1e5..20eccef71 100644 --- a/app/controllers/timelog_controller.rb +++ b/app/controllers/timelog_controller.rb @@ -52,7 +52,7 @@ class TimelogController < ApplicationController format.html { @entry_count = scope.count @entry_pages = Paginator.new @entry_count, per_page_option, params['page'] - @entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).all + @entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a @total_hours = scope.sum(:hours).to_f render :layout => !request.xhr? @@ -60,15 +60,15 @@ class TimelogController < ApplicationController format.api { @entry_count = scope.count @offset, @limit = api_offset_and_limit - @entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).all + @entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).to_a } format.atom { - entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").all + entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").to_a render_feed(entries, :title => l(:label_spent_time)) } format.csv { # Export all entries - @entries = scope.all + @entries = scope.to_a send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv') } end @@ -232,7 +232,7 @@ private end def find_time_entries - @time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).all + @time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).to_a raise ActiveRecord::RecordNotFound if @time_entries.empty? @projects = @time_entries.collect(&:project).compact.uniq @project = @projects.first if @projects.size == 1 diff --git a/app/controllers/trackers_controller.rb b/app/controllers/trackers_controller.rb index 02274d0d3..ec0b9ce3f 100644 --- a/app/controllers/trackers_controller.rb +++ b/app/controllers/trackers_controller.rb @@ -29,14 +29,14 @@ class TrackersController < ApplicationController render :action => "index", :layout => false if request.xhr? } format.api { - @trackers = Tracker.sorted.all + @trackers = Tracker.sorted.to_a } end end def new @tracker ||= Tracker.new(params[:tracker]) - @trackers = Tracker.sorted.all + @trackers = Tracker.sorted.to_a @projects = Project.all end @@ -95,7 +95,7 @@ class TrackersController < ApplicationController redirect_to fields_trackers_path return end - @trackers = Tracker.sorted.all + @trackers = Tracker.sorted.to_a @custom_fields = IssueCustomField.all.sort end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index c5db58988..bb56fb285 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -47,7 +47,7 @@ class UsersController < ApplicationController @user_count = scope.count @user_pages = Paginator.new @user_count, @limit, params['page'] @offset ||= @user_pages.offset - @users = scope.order(sort_clause).limit(@limit).offset(@offset).all + @users = scope.order(sort_clause).limit(@limit).offset(@offset).to_a respond_to do |format| format.html { @@ -60,7 +60,7 @@ class UsersController < ApplicationController def show # show projects based on current user visibility - @memberships = @user.memberships.where(Project.visible_condition(User.current)).all + @memberships = @user.memberships.where(Project.visible_condition(User.current)).to_a events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) @events_by_day = events.group_by(&:event_date) @@ -90,7 +90,7 @@ class UsersController < ApplicationController @user.admin = params[:user][:admin] || false @user.login = params[:user][:login] @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id - @user.pref.attributes = params[:pref] + @user.pref.attributes = params[:pref] if params[:pref] if @user.save Mailer.account_information(@user, @user.password).deliver if params[:send_information] @@ -134,7 +134,7 @@ class UsersController < ApplicationController # Was the account actived ? (do it before User#save clears the change) was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE]) # TODO: Similar to My#account - @user.pref.attributes = params[:pref] + @user.pref.attributes = params[:pref] if params[:pref] if @user.save @user.pref.save diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index a49f8a09a..bf2315321 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -31,7 +31,7 @@ class VersionsController < ApplicationController def index respond_to do |format| format.html { - @trackers = @project.trackers.sorted.all + @trackers = @project.trackers.sorted.to_a retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] @@ -56,7 +56,7 @@ class VersionsController < ApplicationController @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} } format.api { - @versions = @project.shared_versions.all + @versions = @project.shared_versions.to_a } end end @@ -67,7 +67,7 @@ class VersionsController < ApplicationController @issues = @version.fixed_issues.visible. includes(:status, :tracker, :priority). reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id"). - all + to_a } format.api end @@ -117,7 +117,7 @@ class VersionsController < ApplicationController end def update - if request.put? && params[:version] + if params[:version] attributes = params[:version].dup attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) @version.safe_attributes = attributes diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb index e6c4d3119..ade977b41 100644 --- a/app/controllers/watchers_controller.rb +++ b/app/controllers/watchers_controller.rb @@ -53,7 +53,7 @@ class WatchersController < ApplicationController def append if params[:watcher].is_a?(Hash) user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]] - @users = User.active.where(:id => user_ids).all + @users = User.active.where(:id => user_ids).to_a end if @users.blank? render :nothing => true @@ -92,7 +92,7 @@ class WatchersController < ApplicationController def find_watchables klass = Object.const_get(params[:object_type].camelcase) rescue nil if klass && klass.respond_to?('watched_by') - @watchables = klass.where(:id => Array.wrap(params[:object_id])).all + @watchables = klass.where(:id => Array.wrap(params[:object_id])).to_a raise Unauthorized if @watchables.any? {|w| if w.respond_to?(:visible?) !w.visible? diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 723c7191d..9b3981655 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -219,7 +219,7 @@ class WikiController < ApplicationController reorder('version DESC'). limit(@version_pages.per_page + 1). offset(@version_pages.offset). - all + to_a render :layout => false if request.xhr? end @@ -280,7 +280,7 @@ class WikiController < ApplicationController @pages = @wiki.pages. order('title'). includes([:content, {:attachments => :author}]). - all + to_a respond_to do |format| format.html { export = render_to_string :action => 'export_multiple', :layout => false @@ -327,7 +327,7 @@ private def find_existing_or_new_page @page = @wiki.find_or_new_page(params[:id]) if @wiki.page_found_with_redirect? - redirect_to params.update(:id => @page.title) + redirect_to_page @page end end @@ -339,10 +339,14 @@ private return end if @wiki.page_found_with_redirect? - redirect_to params.update(:id => @page.title) + redirect_to_page @page end end + def redirect_to_page(page) + redirect_to :action => action_name, :project_id => page.wiki.project, :id => page.title + end + # Returns true if the current user is allowed to edit the page, otherwise false def editable?(page = @page) page.editable_by?(User.current) @@ -360,6 +364,6 @@ private reorder("#{WikiPage.table_name}.title"). includes(:wiki => :project). includes(:parent). - all + to_a end end diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb index fd700d25e..28b0f2242 100644 --- a/app/controllers/workflows_controller.rb +++ b/app/controllers/workflows_controller.rb @@ -86,9 +86,9 @@ class WorkflowsController < ApplicationController @source_role = Role.find_by_id(params[:source_role_id].to_i) end @target_trackers = params[:target_tracker_ids].blank? ? - nil : Tracker.where(:id => params[:target_tracker_ids]).all + nil : Tracker.where(:id => params[:target_tracker_ids]).to_a @target_roles = params[:target_role_ids].blank? ? - nil : Role.where(:id => params[:target_role_ids]).all + nil : Role.where(:id => params[:target_role_ids]).to_a if request.post? if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) flash.now[:error] = l(:error_workflow_copy_source) @@ -113,9 +113,9 @@ class WorkflowsController < ApplicationController def find_roles ids = Array.wrap(params[:role_id]) if ids == ['all'] - @roles = Role.sorted.all + @roles = Role.sorted.to_a elsif ids.present? - @roles = Role.where(:id => ids).all + @roles = Role.where(:id => ids).to_a end @roles = nil if @roles.blank? end @@ -123,9 +123,9 @@ class WorkflowsController < ApplicationController def find_trackers ids = Array.wrap(params[:tracker_id]) if ids == ['all'] - @trackers = Tracker.sorted.all + @trackers = Tracker.sorted.to_a elsif ids.present? - @trackers = Tracker.where(:id => ids).all + @trackers = Tracker.where(:id => ids).to_a end @trackers = nil if @trackers.blank? end @@ -135,6 +135,6 @@ class WorkflowsController < ApplicationController if @trackers && @used_statuses_only @statuses = @trackers.map(&:issue_statuses).flatten.uniq.sort.presence end - @statuses ||= IssueStatus.sorted.all + @statuses ||= IssueStatus.sorted.to_a end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6b5dd08e0..0cb4c4c00 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -138,9 +138,7 @@ module ApplicationHelper if project.archived? h(project.name) elsif options.key?(:action) - ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0." - url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) - link_to project.name, url, html_options + raise "#link_to_project no longer accepts :action option in Redmine 3.0" else link_to project.name, project_path(project, options), html_options end @@ -157,13 +155,6 @@ module ApplicationHelper end end - # Generates a link to a version - def link_to_version(version, options = {}) - return '' unless version && version.is_a?(Version) - options = {:title => format_date(version.effective_date)}.merge(options) - link_to_if version.visible?, format_version_name(version), version_path(version), options - end - # Helper that formats object for html or text rendering def format_object(object, html=true, &block) if block_given? @@ -185,7 +176,7 @@ module ApplicationHelper when 'Project' html ? link_to_project(object) : object.to_s when 'Version' - html ? link_to_version(object) : object.to_s + html ? link_to(object.name, version_path(object)) : object.to_s when 'TrueClass' l(:general_text_Yes) when 'FalseClass' @@ -247,7 +238,7 @@ module ApplicationHelper end def format_version_name(version) - if !version.shared? || version.project == @project + if version.project == @project h(version) else h("#{version.project} - #{version}") @@ -502,7 +493,7 @@ module ApplicationHelper h(Setting.app_title) else b = [] - ancestors = (@project.root? ? [] : @project.ancestors.visible.all) + ancestors = (@project.root? ? [] : @project.ancestors.visible.to_a) if ancestors.any? root = ancestors.shift b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') @@ -1217,7 +1208,7 @@ module ApplicationHelper source end end - super sources, options + super *sources, options end # Overrides Rails' image_tag with themes and plugins support. @@ -1250,7 +1241,7 @@ module ApplicationHelper end end end - super sources, options + super *sources, options end # TODO: remove this in 2.5.0 @@ -1288,12 +1279,7 @@ module ApplicationHelper end def sanitize_anchor_name(anchor) - if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' - anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-') - else - # TODO: remove when ruby1.8 is no longer supported - anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') - end + anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-') end # Returns the javascript tags that are included in the html layout head diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 4777328b0..315be99fc 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -30,7 +30,7 @@ module GroupsHelper scope = User.active.sorted.not_in_group(group).like(params[:q]) principal_count = scope.count principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page'] - principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all + principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals') diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 8d7f9641c..9760a8ebb 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -63,7 +63,7 @@ module IssuesHelper def render_issue_subject_with_tree(issue) s = '' - ancestors = issue.root? ? [] : issue.ancestors.visible.all + ancestors = issue.root? ? [] : issue.ancestors.visible.to_a ancestors.each do |ancestor| s << '<div>' + content_tag('p', link_to_issue(ancestor, :project => (issue.project_id != ancestor.project_id))) end @@ -204,7 +204,7 @@ module IssuesHelper order("#{Query.table_name}.name ASC"). # Project specific queries and global queries where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]). - all + to_a end @sidebar_queries end @@ -408,7 +408,7 @@ module IssuesHelper if association record = association.class_name.constantize.find_by_id(id) if record - record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding) + record.name.force_encoding('UTF-8') return record.name end end diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index 5e98643db..4aae46475 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -22,7 +22,7 @@ module MembersHelper scope = Principal.active.sorted.not_member_of(project).like(params[:q]) principal_count = scope.count principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page'] - principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all + principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals') diff --git a/app/helpers/my_helper.rb b/app/helpers/my_helper.rb index 8e78dfbe9..5917f26ec 100644 --- a/app/helpers/my_helper.rb +++ b/app/helpers/my_helper.rb @@ -23,11 +23,12 @@ module MyHelper where(:project_id => User.current.projects.map(&:id)). where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt). includes(:project, :tracker, :priority, :assigned_to). - all + references(:project, :tracker, :priority, :assigned_to). + to_a end def documents_items - Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).all + Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).to_a end def issuesassignedtome_items @@ -35,8 +36,9 @@ module MyHelper where(:assigned_to_id => ([User.current.id] + User.current.group_ids)). limit(10). includes(:status, :project, :tracker, :priority). + references(:status, :project, :tracker, :priority). order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC"). - all + to_a end def issuesreportedbyme_items @@ -44,12 +46,13 @@ module MyHelper where(:author_id => User.current.id). limit(10). includes(:status, :project, :tracker). + references(:status, :project, :tracker). order("#{Issue.table_name}.updated_on DESC"). - all + to_a end def issueswatched_items - Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).all + Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).to_a end def news_items @@ -57,15 +60,17 @@ module MyHelper where(:project_id => User.current.projects.map(&:id)). limit(10). includes(:project, :author). + references(:project, :author). order("#{News.table_name}.created_on DESC"). - all + to_a end def timelog_items TimeEntry. where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today). - includes(:activity, :project, {:issue => [:tracker, :status]}). + joins(:activity, :project, {:issue => [:tracker, :status]}). + references(:activity, :project, {:issue => [:tracker, :status]}). order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC"). - all + to_a end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 8e23ccdda..e23ebab99 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -18,6 +18,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module ProjectsHelper + def link_to_version(version, options = {}) + return '' unless version && version.is_a?(Version) + link_to_if version.visible?, format_version_name(version), version_path(version), options + end + def project_settings_tabs tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb index ca8d2537b..0206b160a 100644 --- a/app/helpers/queries_helper.rb +++ b/app/helpers/queries_helper.rb @@ -143,7 +143,7 @@ module QueriesHelper end end - export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + export = CSV.generate(:col_sep => l(:general_csv_separator)) do |csv| # csv header fields csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } # csv lines diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index a39686b3d..15433750a 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -29,7 +29,6 @@ module SearchHelper result << '...' break end - words = words.mb_chars if i.even? result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words) else diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb index cbdc41883..da74aeac2 100644 --- a/app/helpers/sort_helper.rb +++ b/app/helpers/sort_helper.rb @@ -84,7 +84,8 @@ module SortHelper def to_sql sql = @criteria.collect do |k,o| if s = @available_criteria[k] - (o ? s.to_a : s.to_a.collect {|c| append_desc(c)}) + s = [s] unless s.is_a?(Array) + (o ? s : s.collect {|c| append_desc(c)}) end end.flatten.compact sql.blank? ? nil : sql diff --git a/app/helpers/timelog_helper.rb b/app/helpers/timelog_helper.rb index 02532c3f1..c68d2c0c5 100644 --- a/app/helpers/timelog_helper.rb +++ b/app/helpers/timelog_helper.rb @@ -105,7 +105,7 @@ module TimelogHelper def report_to_csv(report) decimal_separator = l(:general_csv_decimal_separator) - export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + export = CSV.generate(:col_sep => l(:general_csv_separator)) do |csv| # Column headers headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) } headers += report.periods 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| diff --git a/app/views/common/_tabs.html.erb b/app/views/common/_tabs.html.erb index 454b5d772..ffb7f2afa 100644 --- a/app/views/common/_tabs.html.erb +++ b/app/views/common/_tabs.html.erb @@ -8,8 +8,8 @@ <% end -%> </ul> <div class="tabs-buttons" style="display:none;"> - <button class="tab-left" type="button" onclick="moveTabLeft(this);"></button> - <button class="tab-right" type="button" onclick="moveTabRight(this);"></button> + <button class="tab-left" onclick="moveTabLeft(this); return false;"></button> + <button class="tab-right" onclick="moveTabRight(this); return false;"></button> </div> </div> diff --git a/app/views/groups/_memberships.html.erb b/app/views/groups/_memberships.html.erb index 777a0df7c..ec275c594 100644 --- a/app/views/groups/_memberships.html.erb +++ b/app/views/groups/_memberships.html.erb @@ -1,5 +1,5 @@ <% roles = Role.find_all_givable %> -<% projects = Project.active.all %> +<% projects = Project.active.to_a %> <div class="splitcontentleft"> <% if @group.memberships.any? %> diff --git a/app/views/projects/settings/_members.html.erb b/app/views/projects/settings/_members.html.erb index ba7bf91f1..392d1d4b5 100644 --- a/app/views/projects/settings/_members.html.erb +++ b/app/views/projects/settings/_members.html.erb @@ -1,6 +1,6 @@ <%= error_messages_for 'member' %> <% roles = Role.find_all_givable - members = @project.member_principals.includes(:member_roles, :roles, :principal).all.sort %> + members = @project.member_principals.includes(:member_roles, :roles, :principal).to_a.sort %> <div class="splitcontentleft"> <% if members.any? %> diff --git a/app/views/timelog/_form.html.erb b/app/views/timelog/_form.html.erb index b51f98dad..955c2d06b 100644 --- a/app/views/timelog/_form.html.erb +++ b/app/views/timelog/_form.html.erb @@ -8,7 +8,7 @@ <% elsif params[:issue_id] %> <%= hidden_field_tag 'issue_id', params[:issue_id] %> <% else %> - <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).all, :selected => @time_entry.project, :include_blank => true) %></p> + <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true) %></p> <% end %> <% end %> <p> diff --git a/app/views/users/_memberships.html.erb b/app/views/users/_memberships.html.erb index c0d8051ae..cd4201727 100644 --- a/app/views/users/_memberships.html.erb +++ b/app/views/users/_memberships.html.erb @@ -1,5 +1,5 @@ <% roles = Role.find_all_givable %> -<% projects = Project.active.all %> +<% projects = Project.active.to_a %> <div class="splitcontentleft"> <% if @user.memberships.any? %> diff --git a/app/views/wiki/edit.html.erb b/app/views/wiki/edit.html.erb index 3a5a4709f..40e6b792a 100644 --- a/app/views/wiki/edit.html.erb +++ b/app/views/wiki/edit.html.erb @@ -23,7 +23,7 @@ <%= fp.select :parent_id, content_tag('option', '', :value => '') + wiki_page_options_for_select( - @wiki.pages.includes(:parent).all - + @wiki.pages.includes(:parent).to_a - @page.self_and_descendants, @page.parent) %> </p> <% end %> diff --git a/app/views/wiki/rename.html.erb b/app/views/wiki/rename.html.erb index c1a8f33ac..85319520d 100644 --- a/app/views/wiki/rename.html.erb +++ b/app/views/wiki/rename.html.erb @@ -13,7 +13,7 @@ <p><%= f.select :parent_id, content_tag('option', '', :value => '') + wiki_page_options_for_select( - @wiki.pages.includes(:parent).all - @page.self_and_descendants, + @wiki.pages.includes(:parent).to_a - @page.self_and_descendants, @page.parent), :label => :field_parent_title %></p> </div> |