How does rails determine the path from an object? - ruby

I have been working on implementing my own ORM. And I was wondering how the rails path helper extracts the ID from the object. For example how would I make this work for my ORM?
#contact = Contact.first
contact_path(#contact)
Any help would be greatly appreciated!
Update:
My object does have an ID attribute and responds to it. But yet the path helper returns an error.

In a nutshell you want to be activemodel compliant. This will make url helpers, form_for(#contact) and so on work.
You also get to (optionally) use a bunch of modules dealing with
things such as validations, dirty attributes etc.
There are only a handful of methods you have to implement. There's also an
ActiveModel::Lint module that tests that your implementations of these
primitives are valid, and which also serves as documentation. In particular you need to implement to_param and persisted?. I think some of the naming stuff only gets used if you do stuff like link_to 'foo', #contact

The method checks to see if you've passed it an object, or an integer. If it's an object and that object has an id method (respond_to?(:id)), it uses its ID. Pretty dead simple.

Related

Ruby on Rails - Where to put these helper type methods

I've been looking around for best practices on where to put some helper methods that do all this calculation / sorting for me but I haven't found a definitive answer yet and was wondering if someone had some good insight for me.
Basically I have an action method that takes a string user input, finds similar words to that string, does a bunch of string manipulation, and then ordering to return an array.
I don't know whether I should have module in /lib, make a controller helper module, ... Where I'm looking for some feedback!
But essentially I just want to:
POST a word to a controller action method
Call a helper method or execute some logic on the word outside of the controller
Have that helper method or wherever that logic will be, return to me the result
Just put that method in your application helper, wherever it is called from it will return the resulting values after processing your logic, you should not over complicate things so the good old application helper is a good place to put the common method used in views and in your controllers
I wouldn't call a helper method from your controller. Personally I would use either a module/plain old ruby object or a concern to handle calculations. The controller stores the object in an instance variable so it can be used througout your views.
Also worth noting are decorators, you should take a look at draper: https://github.com/drapergem/draper

Self-Documenting ActiveRecord Class Files in Rails 4 without attr_accessible

Question:
In a post-attr_accessible Rails 4 world, in what way do you recommend, if at all, annotating your ActiveRecord model class files to communicate its (database) attributes?
Further Thoughts
As part of a Rails 3 -> 4 upgrade, we are making a switch, and happily so, away from attr_accessible and to strong parameters in the controller. I understand and agree with the improvement in security via this switch. If you want to know more about this, the information is out there, and it's not hard to find.
But, I enjoyed, in my Rails 3 world, having those reminders of what attributes made up a class up there at the top of the model file. Especially since we're moving toward a world in which ActiveRecord classes are just DAOs, what else is the class but a collection of database attributes? I don't want to go to the schema.rb file just to remember them.
Am I thinking about this incorrectly? In a DAO world, should I be creating my ActiveRecord model class file and then never opening it again?
I know about the annotate_models gem and used it way back in the day. I was not a fan of having the attributes described in commented-out lines. (unreadable, hackish, fragile)
Thoughts? Opinions?
How about:
Person.column_names
If you are using an IDE or and editor that has a console feature this becomes an easy way to be reminded what attributes there are. I am no Ruby or Rails expert, still pretty new here, but I've been using Rails 4 almost exclusively and it just seems like you wouldn't need to see the attributes that often in the model. The params get whitelisted in the controller because that is where they will usually be used, no? If you don't want to use comments you could store an array of the attributes in the model:
my_attr = [:fname, :lname, :age, :height, :weight]
But is that really any more useful than a comment? Would there be a case of attributes that would have been in attr_accessible that wouldn't be in your whitelist in your controller? It would be trick if you put some code in a rake task that would run every time you ran
rake db:...
that would update the my_attr array in your model so you wouldn't have to remember to do it when you modified the model. I go into my models to add class methods and scopes, so I do see a value in it. But I work in RubyMine so I just click on the DB tab on the left side if I need to be reminded of columns that aren't in my whitelist.

Having trouble navigating Magento documentation

I am brand new to Magento and the documentation, primarily the phpDocs, are difficult to navigate. For example,
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($id);
In the php doc for Class Mage_Eav_Model_Entity_Attribute_Set there is no mention of the method getAttributeSetName() either in inherited methods or otherwise and yet this works.
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($id);
echo $attributeSet->getAttributeSetName();
So I suppose I have several questions.
Can someone explain to me why the documentation is this way?
Where I can find the mysterious getAttributeSetName() method in the phpDocs?
My theory is that there is some inheritance or a design pattern implementation going on that I'm not understanding, maybe someone can shed some light on this for me.
If you really want to fry your brain, take a look at the source code for Mage_Eav_Model_Entity_Attribute_Set and follow the inheritance chain all the way back. You won't find a getAttributeSetName method defined anywhere.
All Magento objects that inherit from Varien_Object can have arbitrary data members set on them. Try this.
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($id);
$attributeSet->setFooBazBar('Value');
var_dump($attributeSet->getFooBazBar());
var_dump($attributeSet->getData('foo_baz_bar'));
var_dump($attributeSet->setData('foo_baz_bar','New Value'));
var_dump($attributeSet->getFooBazBar());
You can also get all the data members by using
var_dump($attributeSet->getData());
but be careful dumping these, because if there's a data object that has a circular reference and you're not using something like xDebug, then PHP will have a fit trying to display the object.
Magento stores data properties in a special _data array property. You can get/set values in this array with getData and setData. Magento also has implemented magic getting and setter methods, so when you say something like
$object->getFooBazBar();
The method getFooBazBar is transformed into the data property foo_baz_bar. and then getData is called using this property. It's a little tricky to get your head around, but once you get it you'll start to see how much time you can save using this pattern.
One side effect of this is, of course, it's impossible to infer what data properties any object might have by looking at it's class file, so there's no phpDocs for these methods.

ActiveResource + Caching

I'm building an application that consumes models through an api with ActiveResource. I noticed that the
#resource ||= #resource.do a query
doesn't work, i.e. If I put something like that in my controller, my application will still query the api. So there is no built in caching that I'm used to with ActiveRecord. Time to expand my knowledge and skill base, ok.
I found this: http://injectisforwizards.com/blog/read-through-caching-of-activeresource/, and while I don't understand this 100% yet, for controller based queries that do .find, this appears to work. But not for any custom queries I have e.g.:
#current_resource ||= Resource.get(:resource_all, :by_account=>#current_account.account_key)
(which hits a custom controller and runs a scope, returning a collection)
I'm working through this and I'll find out what is going, but I'm curious if someone could tell me simpler terms what is going on, what I can do to smooth over caching in ActiveResource to be more like ActiveRecord, how I can tailor this to cache all queries, etc. Anything really would be helpful.
EDIT:
I found this: https://github.com/Ahsizara/cached_resource which looks promising but it is new (and built off that link above)....notable is that it does not seem to handle any sort of collections, but for one resource finds/caches well.
Since you receive a new instance of a controller for each request, caching like that is not going to work. I'm presuming you have something like this:
def show
#resource ||= expensive_request
end
What are you expecting #resource to be when that method executes? The result of something from a previous call to show? Not going to happen.
What you need to do is put things into Rails.cache if you want them to persist between requests. If you use memcached as a back end, this can be very efficient. See the Caching with Rails guide for more information around section 2.5.
In general, a better approach than the ||= method of caching is to define protected methods that are wrapped with memoize to save the results. For example:
def load_resource
expensive_request
end
memoize :load_resource
Remember that this will only apply to subsequent calls to that method within the context of the same request and is not the same as using Rails.cache.

Ruby 1.9.2 + Sinatra - Requiring authentication on certain routes

Before I begin, this is basically a port of an existing ASP.MVC REST style service to Sinatra. I am fairly new to Ruby so dont really know the best practises yet, and the web seems a bit torn on the subject.
So currently in the ASP flavour we have some controllers like so:
public class MyController : Controller
{
[Authenticate]
public ActionResult AccessSecretStuffs()
{...}
public ActionResult AccessPublicStuffs()
{...}
}
Now we use a filter to make sure that any actions with Authenticate check for authentication from the current user before loading the action. The routes setup for these are fairly vanilla, they just map to the controller and actions.
Now in Ruby land using Sinatra you dont tend to have controllers, everything is an action, and as we are purely looking to expose data in a restful way this seems great. However I need to be able to make sure that whenever certain routes are called with Sinatra that it will basically call a bit of code first to check if they can access the action, then if not redirect them to the login page.
I was thinking of just putting in some AOP to cover this, but after a bit of reading everyone says Ruby doesnt need AOP and already provides most of the functionality out of the box. So can anyone shed some light on the best practise for doing this?
Sinatra documentation has a before method that would be applicable, but then I would need to do a before method for every other route method, which isnt ideal. In my mind I just want to declare a route, and then put some sort of annotation/attribute at the end which indicates that something needs to happen...
Hope that makes some sort of sense :)
Ruby doesn't have annotations as such, but Sinatra does provide custom filtering mechanisms.
When defining a route, you can put additional conditions, such as various header values and whatnot. You can also define custom conditions:
set(:auth) do |*roles| # <- notice the splat here
condition do
unless logged_in? && roles.any? {|role| current_user.in_role? role }
redirect "/login/", 303
end
end
end
Then you can define a route like this:
get "/secret", :auth => [:user, :admin] do
...
end
or if you don't need to pass any arguments, before block can take a path as an argument:
before '/secret/*' do
authenticate!
end
You can read more at Sinatra readme page

Resources