Module: RestfulJson::Controller::ActsAsRestfulJson
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/restful_json/controller.rb
Defined Under Namespace
Modules: ClassMethods
Constant Summary collapse
- NILS =
['NULL','null','nil']
Instance Method Summary collapse
- #convert_request_param_value_for_filtering(attr_sym, value) ⇒ Object
-
#create ⇒ Object
The controller’s create (post) method to create a resource.
-
#destroy ⇒ Object
The controller’s destroy (delete) method to destroy a resource.
-
#edit ⇒ Object
The controller’s edit method (e.g. used for edit record in html format).
-
#index ⇒ Object
The controller’s index (list) method to list resources.
-
#initialize ⇒ Object
In initialize we: * guess model name, if unspecified, from controller name * define instance variables containing model name * define the (model_plural_name)_url method, needed if controllers are not in the same module as the models Note: if controller name is not based on model name and controller is in different module than model, you’ll need to redefine the appropriate method(s) to return urls if needed.
-
#new ⇒ Object
The controller’s new method (e.g. used for new record in html format).
-
#show ⇒ Object
The controller’s show (get) method to return a resource.
-
#update ⇒ Object
The controller’s update (put) method to update a resource.
Instance Method Details
#convert_request_param_value_for_filtering(attr_sym, value) ⇒ Object
166 167 168 |
# File 'lib/restful_json/controller.rb', line 166 def convert_request_param_value_for_filtering(attr_sym, value) value && NILS.include?(value) ? nil : value end |
#create ⇒ Object
The controller’s create (post) method to create a resource.
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/restful_json/controller.rb', line 296 def create :create, @model_class @value = @model_class.new(permitted_params) @value.save instance_variable_set(@model_at_singular_name_sym, @value) if RestfulJson.return_resource respond_with(@value) do |format| format.json do if @value.errors.empty? render json: @value, status: :created else render json: {errors: @value.errors}, status: :unprocessable_entity end end end else respond_with @value end end |
#destroy ⇒ Object
The controller’s destroy (delete) method to destroy a resource.
339 340 341 342 343 344 345 |
# File 'lib/restful_json/controller.rb', line 339 def destroy # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 @value = @model_class.find(params[:id].to_s) @value.destroy instance_variable_set(@model_at_singular_name_sym, @value) respond_with @value end |
#edit ⇒ Object
The controller’s edit method (e.g. used for edit record in html format).
289 290 291 292 293 |
# File 'lib/restful_json/controller.rb', line 289 def edit # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 @value = @model_class.find(params[:id].to_s) instance_variable_set(@model_at_singular_name_sym, @value) end |
#index ⇒ Object
The controller’s index (list) method to list resources.
Note: this method be alias_method’d by query_for, so it is more than just index.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/restful_json/controller.rb', line 173 def index t = @model_class.arel_table value = @model_class.scoped # returns ActiveRecord::Relation equivalent to select with no where clause custom_query = self.action_to_query[params[:action].to_s] if custom_query value = custom_query.call(t, value) end self.param_to_query.each do |param_name, param_query| if params[param_name] # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 value = param_query.call(t, value, params[param_name].to_s) end end self.param_to_through.each do |param_name, through_array| if params[param_name] # build query # e.g. SomeModel.scoped.joins({:assoc_name => {:sub_assoc => {:sub_sub_assoc => :sub_sub_sub_assoc}}).where(sub_sub_sub_assoc_model_table_name: {column_name: value}) last_model_class = @model_class joins = nil # {:assoc_name => {:sub_assoc => {:sub_sub_assoc => :sub_sub_sub_assoc}} through_array.each do |association_or_attribute| if association_or_attribute == through_array.last # must convert param value to string before possibly using with ARel because of CVE-2013-1854, fixed in: 3.2.13 and 3.1.12 # https://groups.google.com/forum/?fromgroups=#!msg/rubyonrails-security/jgJ4cjjS8FE/BGbHRxnDRTIJ value = value.joins(joins).where(last_model_class.table_name.to_sym => {association_or_attribute => params[param_name].to_s}) else found_classes = last_model_class.reflections.collect {|association_name, reflection| reflection.class_name.constantize if association_name.to_sym == association_or_attribute}.compact if found_classes.size > 0 last_model_class = found_classes[0] else # bad can_filter_by :through found at runtime raise "Association #{association_or_attribute.inspect} not found on #{last_model_class}." end if joins.nil? joins = association_or_attribute else joins = {association_or_attribute => joins} end end end end end self.param_to_attr_and_arel_predicate.keys.each do |param_name| = param_to_attr_and_arel_predicate[param_name][2] param = params[param_name] || [:with_default] if param.present? && param_to_attr_and_arel_predicate[param_name] attr_sym = param_to_attr_and_arel_predicate[param_name][0] predicate_sym = param_to_attr_and_arel_predicate[param_name][1] if predicate_sym == :eq value = value.where(attr_sym => convert_request_param_value_for_filtering(attr_sym, param)) else one_or_more_param = param.split(self.filter_split).collect{|v|convert_request_param_value_for_filtering(attr_sym, v)} value = value.where(t[attr_sym].try(predicate_sym, one_or_more_param)) end end end if params[:page] && self.supported_functions.include?(:page) page = params[:page].to_i page = 1 if page < 1 # to avoid people using this as a way to get all records unpaged, as that probably isn't the intent? #TODO: to_s is hack to avoid it becoming an Arel::SelectManager for some reason which not sure what to do with value = value.skip((self.number_of_records_in_a_page * (page - 1)).to_s) value = value.take((self.number_of_records_in_a_page).to_s) end if params[:skip] && self.supported_functions.include?(:skip) # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 value = value.skip(params[:skip].to_s) end if params[:take] && self.supported_functions.include?(:take) # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 value = value.take(params[:take].to_s) end if params[:uniq] && self.supported_functions.include?(:uniq) value = value.uniq end # these must happen at the end and are independent if params[:count] && self.supported_functions.include?(:count) value = value.count.to_i elsif params[:page_count] && self.supported_functions.include?(:page_count) count_value = value.count.to_i # this executes the query so nothing else can be done in AREL value = (count_value / self.number_of_records_in_a_page) + (count_value % self.number_of_records_in_a_page ? 1 : 0) else self.ordered_by.each do |attr_to_direction| # this looks nasty, but makes no sense to iterate keys if only single of each value = value.order(t[attr_to_direction.keys[0]].call(attr_to_direction.values[0])) end value = value.to_a end @value = value instance_variable_set(@model_at_plural_name_sym, @value) respond_with @value end |
#initialize ⇒ Object
In initialize we:
-
guess model name, if unspecified, from controller name
-
define instance variables containing model name
-
define the (model_plural_name)_url method, needed if controllers are not in the same module as the models
Note: if controller name is not based on model name and controller is in different module than model, you’ll need to redefine the appropriate method(s) to return urls if needed.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/restful_json/controller.rb', line 145 def initialize super # if not set, use controller classname qualified_controller_name = self.class.name.chomp('Controller') @model_class = self.model_class || qualified_controller_name.split('::').last.singularize.constantize raise "#{self.class.name} failed to initialize. self.model_class was nil in #{self} which shouldn't happen!" if @model_class.nil? raise "#{self.class.name} assumes that #{self.model_class} extends ActiveRecord::Base, but it didn't. Please fix, or remove this constraint." unless @model_class.ancestors.include?(ActiveRecord::Base) @model_singular_name = self.model_singular_name || self.model_class.name.underscore @model_plural_name = self.model_plural_name || @model_singular_name.pluralize @model_at_plural_name_sym = "@#{@model_plural_name}".to_sym @model_at_singular_name_sym = "@#{@model_singular_name}".to_sym underscored_modules_and_underscored_plural_model_name = qualified_controller_name.gsub('::','_').underscore # This is a workaround for controllers that are in a different module than the model only works if the controller's base part of the unqualified name in the plural model name. # If the model name is different than the controller name, you will need to define methods to return the right urls. class_eval "def #{@model_plural_name}_url;#{underscored_modules_and_underscored_plural_model_name}_url;end;def #{@model_singular_name}_url(record);#{underscored_modules_and_underscored_plural_model_name.singularize}_url(record);end" end |
#new ⇒ Object
The controller’s new method (e.g. used for new record in html format).
283 284 285 286 |
# File 'lib/restful_json/controller.rb', line 283 def new @value = @model_class.new respond_with @value end |
#show ⇒ Object
The controller’s show (get) method to return a resource.
275 276 277 278 279 280 |
# File 'lib/restful_json/controller.rb', line 275 def show # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 @value = @model_class.find(params[:id].to_s) instance_variable_set(@model_at_singular_name_sym, @value) respond_with @value end |
#update ⇒ Object
The controller’s update (put) method to update a resource.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/restful_json/controller.rb', line 317 def update :update, @model_class # to_s as safety measure for vulnerabilities similar to CVE-2013-1854 @value = @model_class.find(params[:id].to_s) @value.update_attributes(permitted_params) instance_variable_set(@model_at_singular_name_sym, @value) if RestfulJson.return_resource respond_with(@value) do |format| format.json do if @value.errors.empty? render json: @value, status: :ok else render json: {errors: @value.errors}, status: :unprocessable_entity end end end else respond_with @value end end |