Adding selection functionality in rails app - ruby-on-rails-3

I am learning ruby on rails. So, I created a sample application in which I am displaying some stuffs. Now I want to add the functionality of narrowing down items depending upon user's selection like changing price ranges, selecting type and so on.
Please suggest some articles / tutorials which can help.

Do this through model finders.
e.g.
http://railscasts.com/episodes/37-simple-search-form
http://railscasts.com/episodes/111-advanced-search-form
This tutorial is about scopes... http://railscasts.com/episodes/111-advanced-search-form but is very relevant and actually has some of the simplest examples.
One of the biggest gains from doing the search in the model (as opposed to the controller) is testing. You can now have unit tests, e.g. rspec model tests if you use rspec, just within the model.
Perhaps you want dynamic scope?
Dynamic scopes allow filtering on the fly and method chaining. For example:
Order.scoped_by_customer_id(12)
Order.scoped_by_customer_id(12).find(:all,
:conditions => "status = 'open'")
Order.scoped_by_customer_id(12).scoped_by_status("open")

Related

Finding "orphan" routes, etc, in a Rails app?

We're at a point in our development where there have been many different fingers in our Rails pie, and there are things we know exist currently that are not being used, etc. What I'm looking for is some way of programmatically determining if there are any orphan routes in the controllers, maybe something that will take the output of rails routes and see if there is anything extraneous in the code. Any thoughts?
It sounds like what your looking for is known as code metrics, there's one solutions in particular that I can think of that sort of covers what you need. It's known as the rails_best_practices gem, one of the many things it checks for is unused controller actions. In addition it will inform you that auto generated routes (e.g., index, show, edit, update, etc..) require restricting when not all of them are used.
For instance the following line will create seven RESTful routes for your Foo controller, regardless of whether they're actually ever implemented or not:
resources :foo
But if your controller only makes use of say the index, show, new, create actions it will tell you to add the :only directive to your route mapping for those actions.
There might be some additional options out there that are more inline with what you need, I recommend taking a look at the Ruby Toolbox's code metrics category and seeing what's out there. Here's the link: https://www.ruby-toolbox.com/categories/code_metrics

Remove a database field when deleting property from a class using datamapper

I am using datamapper in a Sinatra application. I currently use the command
DataMapper.finalize.auto_upgrade!
to handle the migrations. I had two Classes (Artists and Events) with a 'has_n' and 'belongs_to' association. An Event 'belonged_to' one Artist and an Artist could have many Events associated with it.
I changed the association to be a many_to_many relationship by deleting the previous parts of the class definition which governed the original one_to_many association in the models and adding
has n, :artists, :through => Resource
to the Event class and the corresponding code to the Artist class. When I make a new Event, an error is kicked off.
#<DataObjects::IntegrityError: events.artist_id may not be NULL
The :artist_id field is a relic of the original association between the two classes. The new many_to_many association is accessed by event.artists[i] (where 'i' is just an integer index going from 0 to the number of associated artists -1). Apparently the original association method between the Artist and Event classes is still there? My guess is the solution to this is to not just use the auto_upgrade method built into datamapper but rather to write an explicit migration. If there is a way to handle this type of change to a database and still have the auto_upgrade method work, that would be great!
If you need more details about my models or anything please ask and I'll gladly add them.
In my experience, DataMapper's auto_upgrade does not work very well -- or, to say the least, it doesn't work the way I expect it to. If you want to add a new column to your model, it will do what it should; try to do anything more sophisticated to a column and it probably won't behave as you expect.
For example, if you create a property of type String, it will initially have a length of 50 characters. If you notice that 50 characters is not enough to hold your string, adding :length => 100 to the model won't be enough to make auto_upgrade change the column's width.
It seems you have stumbled upon another shortcoming, although one may argue that, in your case, maybe DataMapper's behavior isn't that bad (think of legacy databases). But the fact is that, when you changed the association, the Event's artist_id column wasn't removed, and then when you try to save an Event, you'll get an error because the database says it is a required field.
Notice that the error you are getting is not a validation error: DataMapper thinks everything looks ok, but gets an error from the database when trying to save the object.
Hope this helps!
Auto-upgrade is not a shortcoming at all! I think of auto-upgrade as a convenience feature of DataMapper. It's only intended purpose is to add columns for you as far as I know. So it is great for getting a project started quickly, and managing test and dev environments without having to write migrations, but not the best tool for making modifications to a mature, live project.
For that, DataMapper does have migrations! Use the dm-migrations gem. The shortcoming is that they are not very well documented... at all. I'm actually working on changing a current project of mine over to using migrations, and I hope to contribute some instructions to the dm-migrations github wiki. But if you aren't ready to switch to migrations, you can also just update columns manually using an SQL client, and then continue to use auto-upgrade for new columns. That's what I have been doing for 2 years on my project :)

ActiveRecord::Base.send(:descendants) doesn't return all models unless touched

Update: This problem no longer exists in Rails 3.2
I am trying to get an array containing all the models in my rails 3 application. I am trying:
ActiveRecord::Base.send(:descendants)
for the same. A similar discussion happened in the question: Is there a way to get a collection of all the Models in your Rails app?. As pointed out in one of the answers, we need to touch the models for the models to show up. That is precisely the problem I am facing.
There are more than a dozen models in my rails app, but
ActiveRecord::Base.send(:descendants)
returns an array of size two. The array has just User and ActiveRecord::SessionStore::Session models. I don't get the other models untill I touch the model by touching, say invoking Comment.new
How can I get all the models listed without touching all the models?
Another additional piece of information that might be useful is that I am using devise for authentication. Maybe devise is doing things in a desired way as far as User model is concerned and I am not doing those things with the other models.
Thanks a lot in advance.
If cache_classes is on (by default it's on in development, not in production), run this first:
Rails.application.eager_load!
You need to load the models first:
Dir[Rails.root + "app/models/**/*.rb"].each do |path|
require path
end

Ruby on Rails - Model field filters

This is probably a very obvious question but I can't quite figure it out. Is there such a thing in rails as a field, or model filter? Something similar to the concept of a before_filter in controllers. In my situation, we have "time" information from a form that needs to be formatted and verified before being set. Instead of simply applying a validator on the field and returning an error, I would like to make it as user friendly as possible and make an attempt to properly format the data. For example, it would be nice to put in my model something like:
before_filter :formatTimeField, :only=>[:timeField1, :timeField2...etc]
As it is right now, I need to specify mutators for each of these fields, and this seems a little silly to me.
Any ideas? Please let me know if I've left out some crucial information. Thanks in advance!
Check out the documentation for before_validation and the rest of the ActiveRecord callbacks. There are a bunch of calls that get made at various stages in the record creation/modification process:
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
In the case you describe, you could call a before_validation method to try and fix the user's inputs and then validate on that modified data. Thus, if you still can't do anything, you can kick it back to the user for correction.
Also, the RoR Guide has a comprehensive overview of the different hooks: http://guides.rubyonrails.org/active_record_validations_callbacks.html#callbacks-overview.
Hope this helps.

Rails: mixing NOSQL & SQL Databases

I'm looking for the better way (aka architecture) to have different kind of DBs ( MySQL + MongoDB ) backending the same Rails app.
I was speculating on a main Rails 3.1 app, mounting Rails 3.1 engines linking each a different kind of DB ...
... or having a main Rails 3.0.x app routing a sinatra endpoint for each MySQL/MongoDB istance ...
Do you think it's possible ..., any idea or suggestions ?
I notice some other similar questions here, but I think that "mounting apps" is moving fast in Rails 3.1 / Rack / Sinatra and we all need to adjust our paradigms.
Thanks in advance
Luca G. Soave
There's no need to completely over-complicate things by running two apps just to have two types of database. It sounds like you need DataMapper. It'll do exactly what you need out of the box. Get the dm-rails gem to integrate it with Rails.
In DataMapper, unlike ActiveRecord, you have to provide all the details about your underlying data store: what fields it has, how they map the attributes in your models, what the table names are (if in a database), what backend it uses etc etc.
Read the documentation... there's a bucket-load of code to give you an idea.
Each model is just a plain old Ruby object. The class definition just mixes in DataMapper::Resource, which gives you access to all of the DataMapper functionality:
class User
include DataMapper::Resource
property :id, Serial
property :username, String
property :password_hash, String
property :created_at, DateTime
end
You have a lot of control however. For example, I can specify that this model is not store in my default data store (repository) and that it's stored in one of the other configured data stores (which can be a NoSQL store, if you like).
class User
include DataMapper::Resource
storage_names[:some_other_repo] = 'whatever'
# ... SNIP ...
end
Mostly DM behaves like ActiveRecord on steroids. You get all the basics, like finding records (except you never have to use the original field names if your model abstracts them away):
new_users = User.all(:created_at.gte => 1.week.ago)
You get validations, you get observers, you get aggregate handling... then get a bunch of other stuff, like strategic eager-loading (solves the n+1 query problem), lazy loading of large text/blob fields, multiple repository support. The query logic is much nicer than AR, in my opinion. Just have a read of the docs. They're human-friendly. Not just an API reference.
What's the downside? Well, many gems don't take into account that you might not be using ActiveRecord, so there's a bit more searching to do when you need a gem for something. This will get better over time though, since before Rails 3.x seamlessly integrating DM with Rails wasn't so easy.
I dont fully understand your question., like
what is the problem you are facing right now using mongo and MySQL in same app, and
whats the reason for going multiple rails app dealing with different dbs.
Though am not an expert in ruby & rails(picked up few months ago), i like to add something here.
I am currently building the rails app utilizing both mongo and MySQL in the back end. Mongoid & ActiveRecord are the drivers. MySql for transactions and mongo for all other kind of data (geo spatial mainly). Its just straight forward. You can create different models inheriting from mongoid and activerecord.
class Item
include Mongoid::Document
field :name, :type => String
field :category, :type => String
end
and
class User < ActiveRecord::Base
end
And you can query both the way same way (except complex sql joins, also mongoid has some addition querying patterns for Geo spatial kind of queries)
Item.where(:category => 'car').skip(0).limit(10)
User.where(:name => 'ram')
Its a breeze. But there are some important points you need to know
Create your Active record models before the mongoid models. Once mongoid is activated (on rails g mongoid:config - mongoid.yml added) all the scaffolding , and generations works toward mongo db. Otherwise every time you need to delete the mongoid.yml before creating the Activerecord models
And don't use mongoid in a relational way. i know mongoid provides lot of options to define realtions. Like Belongs_to relations stores the refernece id's in child documents. Its quite opposite to the mongo DbRef. Its greatly confusing when leaving the mongo idioms for the favour of active record feel. So try to stick with the document nature of it. Use embed and DbRef whenever necessary. (may be someone corrcet me if am wrong)
Still Mongoid is a great work. Its fully loaded with features.