Rails ActiveRecord override default find - ruby-on-rails

I'm building an API wrapper that will query objects from a third-party API and build them into objects to be used in my Rails environment. To do that, I'm building a set of models that use ActiveRecord (for some of its functionality) but are not database backed. I would like to be able to make a call like this:
obj = MyModel.find(1)
And have the code be something like this:
def MyModel.find id
# check for object in cache
# check for object in db
# grab object from API
# return object
end
Am I going to do something horribly wrong if I override the default find method? Am I approaching this in totally the wrong way?

If you are not using a database, then you do not need ActiveRecord. The entire purpose of ActiveRecord is to give you a mapping to a relational database.
I think what you want is for a class to implement certain pieces of what ActiveRecord provides, and Rails 3 has made those pieces into classes that you can include into regular 'ol classes on an as-needed basis. Look at this article for more details: http://www.rubyinside.com/rails-3-0s-activemodel-how-to-give-ruby-classes-some-activerecord-magic-2937.html
For instance, if you only want validations on a class, you can use include ActiveModel::Validations and then you'll get all of the nice error handling and .valid? and validates presence: true kind of behavior you're used to.
I would also suggest the railscast by Ryan Bates: http://railscasts.com/episodes/219-active-model which goes into more detail.

Related

Using ActiveRecord interface for Models backed by external API in Ruby on Rails

I'm trying to use Models in my Rails application that retrieve information from an external API. What I would like to do is access my data models (which may consist of information resulting from multiple API calls) in a way similar to what an ActiveRecord model would provide (specifically associations, and the same style of chain-able query methods).
My initial instinct was to recreate the parts of ActiveRecord that I wanted and incorporate this API. Not wanting to 'reinvent the wheel' and seeing exactly how much work would be required to add more functionality have made me take a step back and reevaluate how to approach this.
I have found ways to use ActiveRecord without a table (see: Railscast #193 Tableless Model and the blog post here) and looked into ActiveRecord. Because ActiveModel only seems to include Validations I'm not sure that's very helpful in this situation. The workaround to using ActiveRecord without a table seems like the best option, but I suspect there's a cleaner way of doing this that I'm just not seeing.
Here is a gist containing some of the code written when I was trying to recreate the ActiveRecord functionality, borrowing heavily from the ActiveRecord source itself.
My question boils down to: I can get the functionality I want (chaining query methods, relations) by either implementing the workaround to ActiveRecord specified above or recreating the functionality myself, but are these really ideal solutions?
Remember that Rails is still just Ruby underneath.
You could represent the external API as instantiated classes within your application.
class Event
def self.find(id)
#...External http call to get some JSON...#
new(json_from_api)
end
def initialize(json)
#...set up your object here...#
end
def attendees
#...external http call to get some JSON and then assemble it
#...into an array of other objects
end
end
So you end up writing local abstractions to create ruby objects from api calls, you can probably also mix in ActiveModel, or Virtus into it, so you can use hash assignment of attributes, and validations for forms etc.
Take a look at an API abstraction I did for the TfL feed for the tube. service_disruption

Rails validation of non-models

I was just wondering what the recommended approach would be for validating a form that is not based on a model. I agree that generally all validation should be done in models but there are situations where a particular form might not have a corresponding model(s). For example, an arbitrary search form.
Based on my current research, there are two main ways of doing it as far as I can see,
Validate in the controller.
Is it possible to utilise the Rails validations in the controller? I really would prefer to use them over my own custom code.
Create an arbitrary class eg. called SearchForm and include the ActiveRecord::Validations
Should the class be stored with the models (even though it isn't really)?
The posts that recommended this approach indicated you have to stub out a bunch of methods for ActiveRecord such as save, save!, update_attribute, etc. This strikes me as not very Rubyesque at all!
Any other suggestions?
Absolutely #2. ActiveModel::Validations API is what you're looking for
class ArbitrarySearch
include ActiveModel::Validations
attr_accessor :query
validate :query, :presence
end
As for where this should go, yes, it should go in app/models. If you're like me and think the mix of models extending ActiveRecord::Base and those that don't coexisting within the same directory smells funny, consider adding the following to your config/application.rb file
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Now, you can organize your model files in whatever way you like. For me I have
- app
|
|- models
|
|- table
|- tableless
|- observer
and I drop classes like your ArbitrarySearch class into app/models/tableless/arbitrary_search.rb.
There is a great gem to get this and other common functionality you use within ActiveRecord models into generic non-table-based model classes called active_attr.
ActiveAttr is a set of modules that makes it easy to create plain old ruby models with functionality found in ORMs, like ActiveRecord, without reinventing the wheel. Think of ActiveAttr as the stuff ActiveModel left out.

Rails gem/plugin for dynamic custom fields in model

Is there any gem/plugin for ruby on rails which gives the ability to define custom fields in a model at runtime with no need to change the model itself for every different field.
I'm looking for something like Redmine acts_as_customizable plugin which is packaged as a gem usable in the rails way, i.e.
gem 'gemname'
rails g something
rails db:migrate
class Model < ActiveRecord::Base
acts_as_something
end
Here are the CustomField and the CustomValue classes used in Redmine.
Edit:
Since my question is not clear I add a brief use case which explains my need better:
I want users to be able to design their own forms, and collect data
submitted on those forms. An important decision is the design of how
these custom dynamic records are stored and accessed.
Taken from here, in this article approach the problem with different ideas, but they all have drawbacks. For this reason I'm asking if the issue has been approached in some gem with no need to rethink the whole problem.
I'm not aware of a gem that does this, but serialize works quite well and it's a built-in. You get a NoSQL-ish document store backed by JSON/YAML.
If you allow user to create a custom form, you can pass nested arrays et cetera directly into the attribute. However, if you need to validate the structure, you're on your own.
I'm afraid it could be tricky and complicated to do it in ActiveRecoand (generally in standard relational database). Take a look at http://mongoid.org/docs/documents/dynamic.html - this mechanism is using nosql feature.
You can also may try the following trick:
1/ Serialize a hash with your custom fields in the database column, for example { :foo => 'bar', :fiz => 'biz' }
2/ After load a record from database do some metaprogramming and define corresponding methods on the record's singleton class, for instance (assume that custom fields are stored and serialized in custom_fields column):
after_initialize :define_custom_methods
# ..or other the most convinient callback
def define_custom_methods
# this trick will open record's singleton class
singleton_class = (class << self; self; end)
# iterate through custom values and define dynamic methods
custom_fields.each_with_key do |key, value|
singleton_class.send(:define_method, key) do
value
end
end
end
Since rails 3.2 you can use store method. Just include following in your model:
store :properties, accessors: [:property1, :property2, :property3...]
You only need to change your model once (to add properties field to db table). You can add more properties later without altering the schema.
The way this works is by serializing properties hash into YAML and saving it into database. It it suitable for most cases, but not if you'd like to use these values in db queries later.
I don't know a gem, but this can be accomplished be creating a table called custom_fields with a name column and possibly a datatype column if you wanted to restrict fields by datatype.
Then you create a join table for a custom field to your desired table and a value and do whatever validations you want.

Rails: FakeModel runs the same validation too many times

We have created a FakeModel object class which inherits from Object,
to allow working with models who don't have a DB table.
It has the basic functionality of a regular ActiveRecord model.
We also added in the class the following line:
include ActiveRecord::Validations
The problem is this:
A new request is sent to the controller, and creates a new object inheriting from the FakeModel class.
When the validations of that object run, they run more then once.
Too be more specific - with each request sent to the server,
the validations run one time more than the last request.
I'm guessing something here "sticks" on the server-level
(of course, when I restart the server, it resets back to running the validations just once)
What can be the cause of that?
UPDATE :
The ActiveModel solution isn't possible for me because I'm using Rails 2.3.8. I still need to figure out where is the problem.
I would suggest you to use ActiveModel instead of writing your own Model engine from scratch, see this blog post for a tutorial you can also watch this screencast
I'm stabbing the dark here, but it sounds like the validations keep being included every time the model is loaded/saved.
Can you show us where you include it?
In Hyperactive Resource, instead of include we used:
# make validations work just like ActiveRecord by pulling them in directly
require "active_record/validations.rb"
extend ActiveRecord::Validations::ClassMethods

How to write a custom method for an ActiveRecord using 'acts_as_<something>'?

I am using Ruby on Rails 3 and I am trying to use some custom method for an ActiveRecord so that I can do
Account.<my_method_name>
in order to add, for example, some data to the Account object (but without to change the Account data itself).
I heard of acts_as_<something> statement and it is used, if I am not wrong, on building plugins, but I didn't understand if it is what I need. After adding acts_as_<something> maybe I have to write somewhere a method like the following in order to "act" on the current ActiveRecord on which the <my_method_name> is called:
def self.<my_method_name>
...
end
Can someone explain me how to use that? And, if possible, can you make me a real example of its usage?
BTW: is it better to build a plugin or write a lib in the RAILS_ROOT/app/lib folder?
You can look at how to implement here => http://thoughtsincomputation.com/posts/coding-an-acts_as-gem-for-rails-3
For real example -> https://github.com/mbleigh/acts-as-taggable-on
The acts_as* is just way of adding behavior to a class. You can do the same by having a module ActsAs* and including this module in the class. Use the acts_as* only if you want to take arguments while adding this common behavior, otherwise just create a module and include it in the class
In the gem acts_as_taggable_on it makes sense because it takes arguments while adding the behavior.
acts_as_taggable_on :languages,:skills
You question is similar to rails3 gem: acts_as_something

Resources