How does Conditional Validation work in rails - ruby-on-rails

Looking through the rails code, I can't see where conditional validation gets executed... when you pass a string or an symbol to :if it supposedly does an eval for strings and a send for symbols... where does that happen?
Been trying to follow it through the code but I can't find where the if options are split into send or eval and how that all works. Just trying to learn and follow the through how rails does it.
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/validator.rb
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/validations.rb
Thanks!

This method is responsible for all the symbols, strings and lambdas being executed. Seems that Rails is using activesupport callbacks to implement validations.

Related

Rails generate model --orm option missing

When I try to generate a model using the next sentence:
rails g model SupplyRequestProfile name:string{50} active:boolean
It fails, and shows the next single line
No value provided for option '--orm'
But, when I use, skipping the fields and types:
rails g model SupplyRequestProfile
It does the job and all is normal.
I have looked if I use a reserved word of rails for my propertys in http://reservedwords.herokuapp.com/ but there is no one that im using.
The problem is not the config/application.rb, all is ok there.
So, I dont know what could be happen here, but it is like some of my property names or types are wrong or causing some strange behavior on rails generation.
What could be wrong?
Simply putting the fields names with their types inside double quotes will work:
rails generate model SupplyRequestProfile "name:string{50}" "active:boolean"

Is SQL Injection possible here?

I have run a static code analysis tool (brakeman) on a rails app and it has reported some SQL Injection vulnerabilities which I suspect may be false positives. The offending lines look like this:
#things_controller.rb
def index
Thing.select(params[:columns]).where(params[:conditions])
end
I can't figure a way to exploit this, but it does seem rather open-ended, is this safe enough (this controller requires admin access anyway) or can it be exploited?
Ruby is 2.0.0-p247,
Rails is 4.0.0
While rails has some built-in filters for special characters, this is definitely vulnerable:
http://guides.rubyonrails.org/security.html#sql-injection
If you want to test it yourself, run a full scan with sqlmap using the url of this action with a conditions GET parameter

Problems Implementing ActiveModel Dirty Rails 3.2.8

I want to check when attributes on a model have changed. I have attempted to check values != the value on the form before doing a save but that code is really ugly and is not working well at times. Same with using update_column which does not do the validations in my model class. If I use update_attributes without doing something else I will not be able to check when a field has been updated from my understanding. From my web research on Stack Overflow and other sites it appears that using ActiveModel Dirty is the way to go.
I have looked at this: http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
My hope is to use this to check if boolean flags changed on a model after using update_attributes. I attempted to do the minimum implementation as described in the included link. I added the following to my ActiveRecord class:
include ActiveModel::Dirty
define_attribute_methods [:admin]
I tried adding the three attributes I wanted to keep track of. I started with just one attribute to see if I could get it working. I received the following error when I ran an rspec test. Once I removed the argument I had no errors.
Exception encountered: #<ArgumentError: wrong number of arguments (1 for 0)>
After I removed the argument I decided to include similar methods in my model using admin instead of name. Other Rspec tests broke on the save method. However I feel the problem is with how I am implementing ActiveModel Dirty.
I have read on other Stack Overflow posts where commenters stated that this was included in 3.2.8 so I upgraded from 3.2.6 to 3.2.8. I did not understand what that meant so after getting errors I decide just to leave the include ActiveModel::Dirty statement and try to use admin_changed? Of course it did not work.
I have not been able to find anything about how to initially set things up for this other than the link I included here. All the other research I have found assumes that the initial setup was correct and that updating to the current stable version of Rails would take care of their problems.
Any help would be appreciated on how to implement this. Doing the minimal implementation as stated in the link is not working. Maybe there is something else I am missing.
The problem appears to be that ActiveRecord redefines the define_attribute_methods method to accept 0 arguments (because ActiveRecord automatically creates attribute methods for every column in the database table): https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods.rb#L23
This overrides the define_attribute_methods method provided by ActiveModel: https://github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute_methods.rb#L240
Solution:
I figured out a solution that worked for me...
Save this file as lib/active_record/nonpersisted_attribute_methods.rb: https://gist.github.com/4600209
Then you can do something like this:
require 'active_record/nonpersisted_attribute_methods'
class Foo < ActiveRecord::Base
include ActiveRecord::NonPersistedAttributeMethods
define_nonpersisted_attribute_methods [:bar]
end
foo = Foo.new
foo.bar = 3
foo.bar_changed? # => true
foo.bar_was # => nil
foo.bar_change # => [nil, 3]
foo.changes[:bar] # => [nil, 3]
However, it looks like we get a warning when we do it this way:
DEPRECATION WARNING: You're trying to create an attribute `bar'. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc.
So I don't know if this approach will break or be harder in Rails 4...
See also:
Track dirty for not-persisted attribute in an ActiveRecord object in rails
https://github.com/adzap/validates_timeliness/issues/73
Try adding adding =, like this:
define_attribute_methods = [:admin]
That change worked for me. Not sure if it has something to do with this?

Why URI.escape fails when called on ActionView::OutputBuffer?

I'm upgrading an application from Rails 2 to Rails 3. Apparently, calling render() now returns ActionView::OutputBuffer and not String. I need to pass the results of render() to URI.escape(), and this fails with exception...
Here is my brief testing in the console
ob = ActionView::OutputBuffer.new("test test")
URI.escape(ob)
`NoMethodError: undefined method 'each_byte' for nil:NilClass`.
from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:307:in `block in escape'
from ..../ruby/1.9.1/gems/activesupport-3.2.1/lib/active_support/core_ext/string/output_safety.rb:160:in `gsub'
from ..../ruby/1.9.1/gems/activesupport-3.2.1/lib/active_support/core_ext/string/output_safety.rb:160:in `gsub'
from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:304:in `escape'
from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:623:in `escape'
Moreover, calling to_s on OutputBuffer returns same OutputBuffer class, so I cannot even convert this buffer into a honest string?
ob.to_s.class
ActionView::OutputBuffer
Of course, calling URI.escape("test test") returns "test%20test" as expected, so this is not URI problem.
Environment:
ruby 1.9.3p125 (2012-02-16 revision 34643) [i686-linux]
Rails 3.2.1
My question is: Why does this happen and how can I work around this issue?
Update: Apparently, using '' + ob as a form of ob.to_s converts OutputBuffer to String, which effectively works around the problem... But my question 'why does this happen' still remains, e.g. is this a bug, should I report it, or I'm doing something wrong?
This is a bug in Rails:
When calling gsub with a block on an ActiveSupport::SafeBuffer the global variables $1, $2, etc. for referencing submatches are not always properly set (anymore?) when the block is called.
This is why URI.escape (and any other function that uses gsub() will fail on ActiveSupprt::Safebuffer.
There are several discussions about this, apparently the safest route right now is to call to_str before passing SafeBuffer to anything that can call gsub, e.g. URI.encode, escape_javascript and similar functions.
My other quesion about to_s returning the same class - obviously safe buffer will return itself and not a bare String, this is by design. In order to get a true String, .to_str can be used.
This is due to the fact that Rails 3 introduced the concept of safe buffers
In Rails3 your Views are protected by XSS by default by making all rendering be safely escaped unless you explicitly use the raw() helper or html_safe
This is a dumb bug that i'm currently encountering in Rails 5. My stupid workaround was to do something like
ob = ActionView::OutputBuffer.new("test test")
URI.escape(ob.to_sym.to_s)
Again it works, but i'm still looking for a cleaner solution.

How to get generators call other generators in rails 3

I am experimenting with gem development, right now specifically generators. So far I have successfully created two generators that do their job just perfectly. These two generators are in the same directory.
However, right now I have to call each of them separately.
What I'd like to do is just call one generator and have that generator call all the other ones. Just would type
rails g generator_name
and this would call x other generators.
Does anyone know how would I got about doing this?
Help is much appreciated, thanks!
In your generator, you can just call
generate "some:generator" # can be anything listed by 'rails g'
for example:
module MyGem
class InstallGenerator < Rails::Generators::Base
def run_other_generators
generate "jquery:install" # or whatever you want here
end
end
end
By the way, if you are working on Rails 3 gems, this question can also help out:
Rails 3 generators in gem
Another possibility is to use something like
invoke 'active_record:model', 'foo bar:string baz:float'
which is not as clean as generate, but has one advantage: When your generator gets called via rails destroy, this call -- like may other of Thors actions -- will try to revoke the action of the generator you invoke.
There's a catch however: Probably due to Thors dependency management, this only works once per generator you want to call, meaning that a second invoke of the same generator will do nothing. This can be circumvented by using a statement like
Rails::Generators.invoke 'active_record:model', '...', behavior: behavior
instead. In this case you have to explicitly pass through the behavior of your generator (which is a method returning values like :invoke, :revoke and possibly others, depending on which command -- rails generate, rails destroy, rails update, etc. -- called your generator) to achieve the same result as above. If you don't do this, the generator you call with Rails::Generators.invoke will also be executed when running your generator with rails destroy.
Alternatively you could stick to invoke and try to tamper with Thors invocation system. See also here for example.
Generators are based off of Thor, so you can use the apply method.
This is what the Rails Templater gem does. (Here's a walk through the Rails Templater gem.)
Take a look at the scaffold generator that comes with rails.
/Users/XYZ/sources/rails/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
def manifest
record do |m|
#....rest of the source is removed for brevity....
m.dependency 'model', [name] + #args, :collision => :skip
end
end
Here the scaffold generator is using the model generator. So take a look at the dependency method. You can find the API docs for it over here.

Resources