I'd like to better understand how ActiveRecord and Arel handle bound parameters for those cases when I need to use Arel to access SQL features not available in ActiveRecord, but don't want to entirely give up on the functionality I already have in ActiveRecord.
Often, this means doing something along these lines:
selectmanager = User.all.arel
# manipulate selectmanager with arel...
users = User.find_by_sql(selectmanager.to_sql)
While this works, there's a problem if the starting ActiveRecord::Relation isn't something trivial like User.all, but instead something that has bound parameters. When there are bound parameters, selectmanager.to_sql contains $1 in place of the parameter, and examining the SelectManager's contents I see it contains an Arel::Nodes::BoundParam, and Postgres complains:
ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1
Now, the bound values are somehow in the relation (I can see them with the_relation.bound_attributes) and AFAIK, ActiveRecord ultimately uses Arel to generate the query, so somewhere there's something that has all the values, knows how to match them up to the bound parameters, and pass this to the database. But that's lost when a Relation is converted to Arel with the technique above.
So, how can I start with an ActiveRecord::Relation, manipulate it with the full power of Arel (adding joins, unions, recursive CTEs, using wacky operators like <#, etc), then bring it back to the ActiveRecord world without losing bound parameters and values?
(At the moment I'm using ActiveRecord 5.0, and Arel 7.1, but knowing something that works for any version would help.)
Related
I'm writing a Ruby gem that requires to make a very simple query to an unknown database among the next: sqlite, mysql, postgresql.
For now I'm using ActiveRecord to handle this idiosyncrasy but looks like a bit overwhelming for me since I'm not using 99% of the ActiveRecord power.
I need something to play with in the next way:
connection = AbstractConnection.new("adapter", "database" {, "username", "userpass"})
connection.query("select * from table")
Is there any gem that abstracts me of generating the connection to different adapters? Is it using ActiveRecord a good idea here?
If you don't want to use ActiveRecord, you could use:
Sqlite3 gem
MongoDB driver
Pg gem
MySQL driver for Ruby
ActiveRecord provides a much nicer DSL across databases, but if you don't need all the overhead then you might want to invest some time in picking up one of the above.
If, however, you think that you may want to change database type in the future, then I recommend you use ActiveRecord: your code will stay the same and the underlying framework will deal with the changed database type.
Hope this helps!
I have updated active record from 3.2.12 to 4.1.4. Accordingly I have update activesupport also from 3.2.12 to 4.1.4. Now when I do data base queries (h2-data base) I cannot use
mrs = MeasurementResultSample.find_by_duration_and_measurement_result_id(duration, id)
I can oly use
mrs = MeasurementResultSample.where(:duration => duration, :measurement_result_id => id).first
The activerecord-jdbch2-adapter I have upgraded from 1.2.9 to 1.3.9
How can I make my 'find_by' methods using one or more fields working again?
Update:
actually it turned out, that find_by is working but I had to check if the table exsist with the method exists?. What wont work is find_last_by... or find_all_by... or find_first_by... .
As I understand it, Rails is moving away from certain 'magic' method names due to the poor performance of 'method_missing,' upon which they're based.
However, find_by works. So you can re-work your query with:
mrs = MeasurementResultSample.find_by(duration: duration, measurement_result_id:, id)
Amusingly, the implementation behind the scenes is:
def find_by(*args)
where(*args).take
end
http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find_by
Edit:
There's a gem that includes Rails 4 deprecated finders:
https://github.com/rails/activerecord-deprecated_finders
Confusingly it states that find_by... methods aren't deprecated. However, if you've updated ActiveRecord outside Rails it might help.
If not, you could always look at the Rails 3 ActiveRecord code and port the relevant methods across.
Thanks to A Fader Darkly! I finally started to port the code to activerecord 4.1.4. I opted to change the finder methods to where(...).
Here I found some information too what-s-new-in-active-record-rails-4.
It's the cleanest way. I noticed, that I had to use the exist? method in some cases to make sure the table is not nil. I did not have to do this before (in 3.2.12) with inflections used.
I have an ActiveRecord based application that is used via command line utilities. Having the models namespaced in such an application is advantageous for keeping the Object namespace clean.
I'm starting to build a rails application around these ActiveRecord models and, though I have overcome some of my initial troubles with using models in a namespace, I'm finding things are more verbose than I'd like.
What I want is to programmaticaly set a namespace for my ActiveRecord classes when used in the command line utilities and to programmaticaly not set a namespace for these models when used in the Rails app.
I know that the files themselves could be altered at runtime before being required, but I'm looking for something in the Ruby language itself to accomplish this cleanly.
hard to offer a great suggestion without seeing some code, but here are two possibilities.
It sounds like you have two clients for this code. Maybe make it an engine (just a fancy gem), you can add your paths to autoload paths, then use it from the gem without all the railsy crap getting in the way.
Maybe create a constant then reopen it in the models:
in some initializer
ActualNamespace = Class.new
DynamicNamespace = ActualNamespace
in your model file
class DynamicNamespace
class MyModel
end
end
DynamicNamespace::MyModel # => ActualNamespace::MyModel
Then for your command line app
DynamicNamespace = Object
Which is the same as not having a namespace:
DynamicNamespace::MyModel # => MyModel
Now you might wind up having difficulties with some of the Rails magic, which is largely based on reflection. I don't totally know what you'll face, but I'd expect forms to start generating the wrong keys when submitting data. You can probably fix this by defining something DynamicNamespace.name or something along those lines.
Autoloading, is likely to also become an issue, but I think you can declare autoload paths somehow (I don't know for sure, but googling "rails autoloading" gives some promising results, looks like it just hooks into Ruby's autoloading -- though I think this is going away in Ruby 2.0) worst case, you can probably define a railtie to eager load the dirs for you. This is all a bit out of my league, but I'd assume you need the railties defined before the app is initialized, so you may need to require the railtie in config/application.rb
Unfortunately, at the end of the day, when you start deviating from Rails conventions, life starts getting hard, and all that magic you never had to think about breaks down so you suddenly have to go diving into the Rails codebase to figure out what it was doing.
I'm trying to create a Rails app without a persistence layer (ActiveRecord, MongoMapper, etc). I've used --skip-active-record on rails new nice_app. This has changed the config/application.rb, but when I try to create new "model" with Rails generate - rails g model nice_class - it fail like a noob with:
No value provided for required options '--orm'
So, if I skip ActiveRecord I can't use Rails generators ?
Note the tasks that get called when you run rails g model nice_class:
invoke active_record
create db/migrate/20111227183458_create_nice_classes.rb
create app/models/nice_class.rb
invoke rspec
create spec/models/nice_class_spec.rb
The first thing you notice, is that it's using ActiveRecord to generate the model. Besides that, though, it's not doing a lot: creates a file in the migrations folder (which you don't need), another file in the model folder (which you do need), and a file in the test or spec folder (which you 'should' need). You can make these yourself if you want want, they are pretty close to being empty anyway.
For specifics about models not based on ActiveRecord, take a look at Ryan Bates' "Tableless Models" Railscast available here: http://railscasts.com/episodes/193-tableless-model.
If you are going to be making these kinds of non-ActiveRecord models a lot, you can write your own generator that does exactly what you want.
Best of luck.
The models that are generated by the Rails generators are subclasses of ActiveRecord, which only really makes sense in the context of an app with an ORM. You could certainly create models that aren't subclasses of ActiveRecord (and thus not associated with any ORM), but you'd have to do that manually.
For a while, I've been working on building a little Ruby library to interface with CouchDB, a neat little document database with a HTTP interface. Key features are:
document objects are glorified hashes
the JavaScript Map/Reduce functions are written in native Ruby, and parsed into JavaScript using S Expressions
you can interface with multiple Couch databases
it should integrate well with micro-frameworks like Camping
I want to be able to do something like this:
#recipes = Recipes.all
Where "Recipes" is a class defining a couple of required keys that the document has (the class name is automatically used as a "kind" key).
But then in tough times I might want to do something like this:
#recipes.each do |recipe|
recipe.cost = "too much!!"
recipe.push!
end
Now, obviously to be able to "push" like that, I either need the database to be.. somewhere in scope.. or for the document object itself to hold a reference to the database object? How is this done in well-established ORMs like ActiveRecord?
I don't want to have to do, you know, recipe.push!(#couch_database_object), or whatever, because that's yucky! But I don't wan to be some scope-polluting scumbag.
Any advice?