Merge branch '21535-multi-wf-delete'
[arvados.git] / services / api / app / controllers / application_controller.rb
index 1fbd65fd828841fa4e5806949ef9aac0c4445dee..b1e2a4008fe8943c29a08dcfc5be25e302dfc280 100644 (file)
@@ -29,6 +29,9 @@ class ApplicationController < ActionController::Base
   include DbCurrentTime
 
   respond_to :json
+
+  # Although CSRF protection is already enabled by default, this is
+  # still needed to reposition CSRF checks later in callback order.
   protect_from_forgery
 
   ERROR_ACTIONS = [:render_error, :render_not_found]
@@ -120,7 +123,7 @@ class ApplicationController < ActionController::Base
     attrs_to_update = resource_attrs.reject { |k,v|
       [:kind, :etag, :href].index k
     }
-    @object.update_attributes! attrs_to_update
+    @object.update! attrs_to_update
     show
   end
 
@@ -228,16 +231,18 @@ class ApplicationController < ActionController::Base
     @objects = model_class.apply_filters(@objects, @filters)
   end
 
-  def select_for_klass sel, model_class
+  def select_for_klass sel, model_class, raise_unknown=true
     return nil if sel.nil?
     # Filter the select fields to only the ones that apply to the
     # given class.
     sel.map do |column|
       sp = column.split(".")
-      if sp.length == 2 && sp[0] == model_class.table_name
+      if sp.length == 2 && sp[0] == model_class.table_name && model_class.selectable_attributes.include?(sp[1])
         sp[1]
       elsif model_class.selectable_attributes.include? column
         column
+      elsif raise_unknown
+        raise ArgumentError.new("Invalid attribute '#{column}' of #{model_class.name} in select parameter")
       else
         nil
       end
@@ -495,12 +500,23 @@ class ApplicationController < ActionController::Base
     @orders = []
     @filters = []
     @objects = nil
+
+    # This is a little hacky but sometimes the fields the user wants
+    # to selecting on are unrelated to the object being loaded here,
+    # for example groups#contents, so filter the fields that will be
+    # used in find_objects_for_index and then reset afterwards.  In
+    # some cases, code that modifies the @select list needs to set
+    # @preserve_select.
+    @preserve_select = @select
+    @select = select_for_klass(@select, self.model_class, false)
+
     find_objects_for_index
     if with_lock && Rails.configuration.API.LockBeforeUpdate
       @object = @objects.lock.first
     else
       @object = @objects.first
     end
+    @select = @preserve_select
   end
 
   def nullable_attributes
@@ -586,10 +602,10 @@ class ApplicationController < ActionController::Base
       :self_link => "",
       :offset => @offset,
       :limit => @limit,
-      :items => @objects.as_api_response(nil, {select: select_for_klass(@select, model_class)})
+      :items => @objects.as_api_response(nil, {select: @select})
     }
     if @extra_included
-      list[:included] = @extra_included.as_api_response(nil, {select: select_for_klass(@select, model_class)})
+      list[:included] = @extra_included.as_api_response(nil, {select: @select})
     end
     case params[:count]
     when nil, '', 'exact'