What's the best way to sanitize destroy_all - Rails - sql

I have the following controller in Rails:
class FooController < ApplicationController
def delete_foo(bar):
Foo.destroy_all("foo = '#{#bar}'")
Is
Foo.destroy_all("foo = ?", #bar)
always valid?

destroy_all works on a relation. Why not do
Foo.where(foo: bar).destroy_all

Foo.destroy_all("foo = ?", #bar), This is invalid.
From apidoc, we will find:
destroy_all(conditions = nil) public
destroy_all method only accepts a single argument, the argument can be a string, array, or hash. You cannot pass two arguments.
So you can write like this:
Foo.destroy_all("foo = #{#bar}")
Foo.destroy_all(foo: #bar)
Foo.where(foo: #bar).destroy_all

Related

What runtime code can I write to extract the type notations as defined by Sorbet, to display to the user?

Is there a way to inspect the type notations in ruby/sorbet?
I actually want to display those values in a form somewhere and instead of hardcoding in values like "this can be nil or a String", I want to instead use the code I've defined by the sig { ... }.
Example pseudo-code:
class User
extend T::Sig
sig { returns(T.nilable(String)) }
def foo
...
end
end
Sorbet.return_type(User, :instance_method, :foo) # returns '[nil, String]' or similar
I believe this is what I am looking for:
T::Utils.signature_for_method
In action:
T::Utils.signature_for_method(User.new.method(:daily?)).return_type
=> #<T::Types::Union:0x0000000132198da8
#types=[#<T::Types::Simple:0x0000000132198f60 #name="TrueClass", #raw_type=TrueClass>, #<T::Types::Simple:0x0000000132198e98 #name="FalseClass", #raw_type=FalseClass>]>

How to pass ActiveRecord model class to Resque

Let's say I have the following Resque job:
class Archive
#queue = :file_serve
def self.perform(repo_id, branch = 'master')
repo = Repository.find(repo_id)
repo.create_archive(branch)
end
end
What if I wanted to make this more generic by passing an object id and the object's class so that I can do something like this:
class Archive
#queue = :file_serve
def self.perform(object_class, object_id, branch = 'master')
object = object_class.find(object_id)
object.create_archive(branch)
end
end
This doesn't work, obviously, and I don't have a sense for what I should be doing, so if anyone can give some guidance, that would be really appreciated!
I would pass the name of the class to the job, rather than the class itself. Then you could call constantize on the name to get the class back, and call find on it. eg.
def self.perform(class_name, object_id, branch = 'master')
object = class_name.constantize.find(object_id)
object.create_archive(branch)
end

Increment integer on save in Rails 3?

I have the following code in my Rails 3 application:
def like
#suggestion = Suggestion.find(params[:id])
Suggestion.update_all("votes = (votes + 1)")
redirect_to suggestions_url
end
def dislike
#suggestion = Suggestion.find(params[:id])
Suggestion.update_all("votes = (votes - 1)")
redirect_to suggestions_url
end
It's working, but rather than updating the current suggestion it's updating them all. So I changed it to:
def like
#suggestion = Suggestion.find(params[:id])
#suggestion.update_all("votes = (votes + 1)")
redirect_to suggestions_url
end
def dislike
#suggestion = Suggestion.find(params[:id])
#suggestion.update_all("votes = (votes - 1)")
redirect_to suggestions_url
end
but then I get:
undefined method `update_all' for #<Suggestion:0x007f87c2b918a0>
So then I tried #suggestion.update_attribute(:votes, '1') but that resets the value to 1 instead of incrementing it.
What's the correct way to achieve this? I just want the integer (votes) of the current suggestion to increment/decrease by 1 on each save.
I've also tried the following with no luck:
def like
#suggestion = Suggestion.find(params[:id])
#suggestion.increment(:votes)
redirect_to suggestions_url
end
This seems more suitable in the model. I suggest creating a like method inside the model like so:
def like
self.increment!(:votes)
end
Now you can do something like this:
#suggestion = Suggestion.find(params[:id])
#suggestion.like
Note: increment!, with the exclamation point also performs the save action
A couple things. It sounds like what you want is a controller action that increments an attribute by one. You were probably closest with the code
#suggestion.update_attribute(:votes, '1')
If you check the documentation for that method, it sets the value of the attribute votes to the second arguement, the string '1', on the object, #suggestion, and its corresponding row in the database. Instead of setting it to '1', you want to set it to the incremented value:
#suggestion.update_attribute(:votes, #suggestion.votes + 1)
Ethan suggested using the convenience method, increment!, which works just the same.
Now, if you wanted to actually auto-increment each time the object gets saved (as in something else about the object gets altered, you'd want to use the :before_save callback with increment without the bang.

How to stub a method which does not have a return value

I am using Mocha, and I want to stub a method which does not have a return value.
It looks something like this
def some_method
increment_counter+=1
database_model.update_attributes(:column => "something")
end
how do I test teh functionality of this method, and see if the database model is updated?
def some_method
increment_counter+=1
database_model.update_attributes(:column => "something")
updated_database_model = Model.find(database_model.id)
updated_database_model.column.should == "something"
end

How do I use a `scope` to find all the records for a model?

I have:
scope :all_somethings, lambda { find(:all) }
But this returns an array (and not a ActiveRecord::Relation), and so I if I called order on it, I get an error:
#somethings = current_user.somethings.all_somethings.order("created_at desc")
undefined method `order' for #<Array:0xb6ebedc2>
Why wouldn't you just do
#everything = MyModel.all
You should just be able to remove the "all_somethings" from your line:
#somethings = current_user.somethings.order("created_at desc")