I thought I understood the difference between require and include with the help of this this thread.
Then I stumbled on this piece of code from the github page of the bcrypt-ruby gem. Why are they using both methods? So first single models are going to be loaded but then again through include all the functions?
require 'bcrypt'
class User < ActiveRecord::Base
# users.password_hash in the database is a :string
include BCrypt
.....
require loads a ruby file, making the BCrypt module available to your ruby code. It does not, necessarily have to be in the same file as the class you're including the module in.
require can also be used to make a ruby class defined in that file available (for instance, other classes you've defined in your project). As it's in a gem, bcrypt is on the ruby path, if it's a file in your project you may need to reference the full path, or use require_relative.
include takes the code in the bCrypt module and includes it to your User class, providing User with the methods and attributes declared in the BCrypt module.
require loads the class.
include actually puts it inside the User class, e.g., including the module's methods as part of the definition of the User class.
The question you reference is pretty explicit about the difference.
Related
I have a Rails project that I have been working on for a while. Like many Rails projects I have a User class. In one of my controllers I need to access some methods from a gem I am using. The example code from the gem demonstrates using an include to a particular gem module. I'm not going to use the actual gem here because it is not important to the question. I have no control over this gem and I need functionality from the module.
include GemName::Module
The problem is that the Gem includes its own User class directly under the module I have included in my controller. This results in calls to my own User class to methods not defined in the gem's user class failing:
User.working?(:test_user)
NoMethodError (undefined method `working?' for GemName::Module::User:Class):
What I would like to do is be able to include the module in my controller and be able to use my application's User class in that same controller.
I have tested the following workarounds, both of which seem to work, neither of which I am particularly happy with:
Create a new constant to refer to my own user class before including the gem module.
LocalUser = User
include GemName::Module
Do not include the module and explicitly call any classes I may need with the fully namespaced call.
GemName::Module::Class.method
I realize I could namespace my User class but that would involve a lot a refactoring around my codebase and I don't really love the idea anyway. This controller calls classes from the gem about 20 times and my own User class exactly once. The controller never calls the gem's User class. If possible, I'd love to force the call to my own User class to refer to the my non namespaced class explicitly and keep the include to the gem module.
Hopefully there is an elegant solution which will increase my understanding of namespaces in Ruby
Just after posting the question, I thought "What if I simply add :: in front of User when calling my own non-namespaced class?"
Sure enough, it works.
::User.working?(:test_user)
Calls my own User class.
I'm leaving the question and this answer up in case it helps others.
Just curious on how things autoloading works in rails
app/models/base_facebook_object.rb
class BaseFacebookObject
end
In the file where I require it,
app/models/fb_campaign.rb
class FbCampaign < BaseFacebookObject
end
But the above doesn't work as it says BaseFacebookObject not defined?
Do I always have to require the base object file in such cases?
require "#{Rails.root}/app/models/base_facebook_object"
Thanks in advance
The autoloader will resolve unfound constant. In your case if you call FbCampaign it will check for the file fb_campaign.rb, then during the loading will find BaseFacebookObject and load base_facebook_object.rb
In other words, no requires needed. Actually you should never use require in a RoR application except for std lib not yet loaded (eg. securerandom, base64 etc. ) or files into a lib/non-autoloaded path.
I'm brand new to rails (and ruby) and having a a lot of trouble with accessing different namespaces. Specifically, I can't access the namespace of the flickraw gem from within a controller class:
class ImageSourcesController < ApplicationController
def show
list = flickr.photos.getRecent
...
end
end
Calling this method, I get the response:
undefined local variable or method `flickr' for #<ImageSourcesController:0x00000005006658>
I am using bundler, which I thought ensured that the methods of all gems in the gemfile are required by rails.
EDIT: I'm stupid, turns out I just needed to reset the server!
It is a good idea to create an initializer for flickraw:
# config/initializers/flickraw.rb
FlickRaw.api_key= ENV['FLICKR_API_KEY']
FlickRaw.shared_secret= ENV['FLICKR_API_SECRET']
If you are creating a open source app you may want to use ENV variables to store your API key and shared secret. The dotenv gem is a really nice tool for that.
You also seem to be confused about namespaces in Ruby. Ruby doesn't actually have namespaces in the same way as for example PHP which has a special keyword and namespace accessors.
Ruby has modules which act as both namespaces (grouping classes, constants etc.) and traits. Foo::Bar.create() is an example of accessing a class method on a "namespaced" class.
module Foo
class Bar
def create
end
end
end
Your flickraw example is simply accessing nested properties (which does'nt really have anything to do with namespaces):
flickr.photos.getRecent
Your taking the object flickr (which flickraw creates when we require flickraw) and sending it the message photos which returns a FlickRaw::Flickr::Photos instance.
We then send the message getRecent to flickr.photos
I would like to use the distance_of_time_in_words method in the date_helper.rb Rails file (see on Github) in an non-Rails Ruby project.
How can I include it? It requires other files, so how to include them?
I don't want to include all of Rails because that would slow down the development process.
Ruby 1.9.3
This method, distance_of_time_in_words is in actionpack/lib/action_view/helpers/date_helper.rb. So you should require 'action_view' and action_view/helpers to load this method. And the method is defined in module ActionView::Helpers::DateHelper, you can include it in your class. The method is an instance method.
require 'action_view'
require 'action_view/helpers'
class Klass
include ActionView::Helpers::DateHelper
end
c = Klass.new
c.distance_of_time_in_words( ...... )
If this is the only thing you want from it, then I'd just go take the source code and hack it to remove the dependencies (which appears to just be some I18n translations. To support the hack, you can probably translate this test suite.
Why would I do this instead of using the gem? Because it's just such an enormous dependency. It's so enormous that you actually notice it loading all that code. I'd rather rip out the method and hack it to work than depend on all of that (again, assuming this is the only thing you want from the lib).
What is the recommended way to extend class behavior, via class_eval and modules (not by inheritance) if I want to extend a class buried in a Gem from a Rails 3 app?
An example is this:
I want to add the ability to create permalinks for tags and categories (through the ActsAsTaggableOn and ActsAsCategory gems).
They have defined Tag and Category models.
I want to basically do this:
Category.class_eval do
has_friendly_id :title
end
Tag.class_eval do
has_friendly_id :title
end
Even if there are other ways of adding this functionality that might be specific to the gem, what is the recommended way to add behavior to classes in a Rails 3 application like this?
I have a few other gems I've created that I want to do this to, such as a Configuration model and an Asset model. I would like to be able to add create an app/models/configuration.rb model class to my app, and it would act as if I just did class_eval.
Anyways, how is this supposed to work? I can't find anything that covers this from any of the current Rails 3 blogs/docs/gists.
I do this as follows, first add a file to config/initializers where you can require the files that contain your extensions:
# config/initializers/extensions.rb
require "#{Rails.root}/app/models/category.rb"
require "#{Rails.root}/app/models/tag.rb"
Then you can just re-open the classes and add whatever else you need:
# app/models/category.rb
class Category
has_friendly_id :title
end
Only downside is that the server has to be restarted for any changes to these files to take effect, not sure if there is a better way that would overcome that.
You can use rails_engine_decorator gem:
https://github.com/atd/rails_engine_decorators
Just add in your Gemfile:
gem 'rails_engine_decorator'
And user class_eval in your decorators:
/app/decorators/models/category_decorator.rb
/app/decorators/models/tag_decorator.rb
It works for me. I hope you find it useful!