How import a helper file that isn't a controller helper? - ruby-on-rails

Suppose I have a random file in a rails app: myapp/app/random_folder/random_helper.rb.
How can I load / require this file in the rails console?
Example
I have the file myapp/spec/spec_helper.rb and I want to require/load those helpers in the rails console.
What I've tried
I tried
require 'spec_helper'
require_relative 'spec/spec_helper.rb'
require_relative 'spec/spec_helper'
require_relative 'spec_helper'
but none of these approaches work.

It was a bug between the keyboard and chair. This does work:
require_relative 'path/to/some_helper'
Read the error message carefully because after loading the helper, an error may be produced, which is very different to a failure to load the helper file at all.
In my case, I saw NoMethodError: undefined method 'configure' for RSpec:Module and mistook it for an inability to load the helper file, but it was in fact loading the helper file but an error resulted from something in the helper file.
I will not accept this answer because it may not be the best way to load a random helper file, but hopefully it may be useful to someone else.

Related

Accessing modules in Rails lib folder

There are probably hundreds of these questions on here but I haven't been able to get one to work yet. I'm using Rails 6 and I always have trouble writing custom modules.
I have a file for creating email tokens: lib/account_management/email_token.rb
module AccountManagement
module EmailToken
def create_email_token(user)
....
end
end
end
Then in my controller I have tried all kinds of things:
require 'account_management/email_token'
include AccountManagement::EmailToken
Calling it with: create_and_send_email_token(user)
At one point I added config.eager_load_paths << Rails.root.join('lib/account_management/') but I didn't think you still had to do that.
Whenever I try to call the controller action I get one of a few error messages:
*** NameError Exception: uninitialized constant Accounts::SessionsController::EmailToken
#this happens if I try to manually send through the rails console
(although inside of a byebug I can call require 'account_management/email_token' and it returns
true.
Most commonly I get:
NoMethodError (undefined method `create_email_token' for #<Accounts::SessionsController:0x00007ffe8dea21d8>
Did you mean? create_email):
# this is the name of the controller method and is unrleated.
The simplest way to solve this is by placing your files in app/lib/account_management/email_token.rb. Rails already autoloads any subdirectory of the app folder*.
/lib has not been on the autoload paths since Rails 3. If you want to add it to the autoload paths you need to add /lib not /lib/account_management to the autoload/eager loading paths. In Zeitwerk terms this adds a root where Zeitwerk will index and resolve constants from.
config.autoload_paths += config.root.join('lib')
config.eager_load_paths += config.root.join('lib')
Note that eager_load_paths is only used when eager loading is turned on. Its turned off by default in development to enable code reloading.
/lib is added to $LOAD_PATHso you can also manually require the file with:
require 'account_management/email_token'
See:
Autoloading and Reloading Constants (Zeitwerk Mode)
Rails #37835

How do I reuse Rspec let expressions across spec files?

I'd like to dry up some of my spec files that share some of the same let expressions by shoving them into a module (or by doing something else you might suggest). When I do that I'm getting an error when I run the spec:
undefined method `let' for SpecShared:Module (NoMethodError)
I'm requiring the module in rails_helper.rb
I'm requiring rails_helper.rb in my module
It seems like the module is either not requiring rails_helper.rb properly, or needs to require something else. What else/instead would I need to do to make this work?
You will want to create a shared context:
https://www.relishapp.com/rspec/rspec-core/v/3-5/docs/example-groups/shared-context

How can I create a custom exception in my Rails application?

I am trying to create custom exceptions in rails, but I 've problem with my designed solution.
Here what I've done so far:
-Create in the app/ folder a folder named errors/ with a file exceptions.rb in it.
app/errors/exceptions.rb:
module Exceptions
class AppError < StandardError; end
end
In one of my controllers, tried to raise it:
raise Exceptions::AppError.new("User is not authorized")
But when I call the controller's action, here is what I get:
NameError (uninitialized constant Exceptions::AppError
Did you mean? TypeError
KeyError
IOError
EOFError
Did you mean? TypeError
KeyError
IOError
EOFError
):
I think I don't have fully understood how to create new directories and files, and use them.
I've read that everything created in the app dir, is eager loaded, so I can't understand where is the problem.
Short version: this is about rails' automated code loading - the fact that in this case the files contain exceptions doesn't matter (see guide on the subject for more details)
Rails would try to load this from exceptions/app_error.rb, in any of the files that are on its auto load path. Because you file naming doesn't match this, it can't find the definition and you get a NameError.
If you don't care about code reloading (and you might not for this sort of content) then you can keep the files as they are but require them in an initialiser (ensure that app/errors is in the load path):
require 'exceptions'
If not then you'll have to rearrange your files to match. If you add app/errors to rails' autoload path and keep the files as is, then it should work. If you don't want to change the autoload path then you'd have to mode it to somewhere in the autoload path and ensure the nesting of modules reflects the organization on disk.
Personally I'd probably stick these in lib and require them with an initialiser

Where do I put an extension to open_uri

I'm trying to fetch an image from Twitter:
open("http://api.twitter.com/1/users/profile_image/barackobama.png?size=bigger")
But I get:
RuntimeError: redirection forbidden: http://... -> https://...
There is an open issue and it seems that I can use an extension to open_uri but I don't know how it works. For example, if I place it in lib/ or if I paste the module in the console, it still doesn't work. Any idea?
I think the proper place to put such a patch is in a file inside config/initializers, i.e. config/initializers/open_uri_allow_unsafe_redirects_patch.rb. You have to require 'open-uri' before reopening the OpenURI module:
require 'open-uri'
module OpenURI
# the rest of the file here...
end
Then you have to call open passing the option allow_unsafe_redirects set to true:
open('http://api.twitter.com/1/users/profile_image/barackobama.png?size=bigger',
allow_unsafe_redirects: true)
You can find more informations about initializer files on the Ruby on Rails guide

How to test a helper within a gem with rspec?

I already published my first rails gem but not yet with any tests included. This gem is just a simple helper which I want to test with rspec. But I have no idea how I can test a helper within a gem with rspec.
I tried to create a file spec/helper/development_ribbon_helper_spec.rb:
require 'spec_helper'
describe DevelopmentRibbonHelper do
end
But when I execute rspec I get this error:
development_ribbon_helper_spec.rb:3:in `<top (required)>': uninitialized constant DevelopmentRibbonHelper (NameError)
You can find the whole source code on github.
It looks like you may be trying to write a rails engine gem, correct? Since your helper file is located outside of lib/, your spec_helper will need to know how to load your rails engine.
One way to do this is to create a dummy rails app in your spec/ directory. This setup is well-described in this post: http://reinteractive.net/posts/2-start-your-engines.
Alternatively, you can move the helper file into lib/development_ribbon and require it in your development_ribbon.rb file:
require "development_ribbon/development_ribbon_helper"
Then, in your rails apps that use the gem, you could include the helper in application_helper.rb
module ApplicationHelper
include DevelopmentRibbon::DevelopmentRibbonHelper
end

Resources