Difference between helper files and lib files in rails - ruby-on-rails

What exactly is the difference between helper files and lib files in rails? When should these files be used appropriately?

Helpers in Rails are used to organize helpers in the views. So you can create a method in some helper module, say:
module SomeModule
def markdown(string)
#some behaviuor
end
end
and then use it in the view: markdown("Hello world").
The Lib folder should keep the parts of your code that are not completely relevant to models, controller, helpers or views. Say you implement your own web crawler in separate class. It is better to keep it in lib/my_crawler.rb.

helpers is a mixins (modules) otherwise in /lib you can place classes and whole libraries

Related

Helper directory in rails

Will a file in helper directory included in all controllers?. I didn't find any good explanation regarding this. I have 2 custom directories in my controller( like admin, for normal user). Do I have same directory structure at my helper?. Is Helper name same as controller name only for readability?
By default all helper files under app/helpers are included in all controllers. As such, it doesn't matter how you structure what's inside helpers folder. If you really want to enforce controller to only include matching helper then set config.action_controller.include_all_helpers in config to false.
See comment section for details: https://github.com/rails/rails/blob/b5db73076914e7103466bd76bec785cbcfe88875/actionpack/lib/action_controller/metal/helpers.rb
Helper is just a ruby module which is openly available for views and controllers. You should never keep your code in helper if you do not want it to expose to views.
If you want to use helper methods for all your controller and views. Then you can add methods to application helper and include it to application controller. However if you don't want to expose methods to views, then you can use rails concerns. create a methods inside it and include it inside different controllers.
No helper do not name the same name only for readability. you still need to include inside your same name controller to call functions if you want to use it inside controller. But you can still use inside views methods with same name.

what is the correct way to add classes to a controller in rails?

If i need to add (project specific) classes to my controler in rails, what is the correct way/place to put and "include" them/there .rb files? (quotes for: not the ruby keyword include)
I am new to rails, and did not find the correct way. LIB sounds like for more public libraries and - what I have learned - is not reloaded per default in dev mode.
sure, I could put all in controler.rb, but ...
the anser for me:
First: there are no rules, if you keep in mind (or learn like me) the rails rules:
NameOfCla -> name_of_cla(.rb) <-- not using class as word for clearence
name your class how you like:
class ExtendCon #<--- not using controller here for clearence
....
put it in a file extend_con.rb, wait for the path explaination, please. if you named your class 'MYGreatThing' it will be 'm_y_great_thing' (never testet that), so avoid chineese charachters
if your controller uses
#letssee=ExtendCon.new
rails learns that class and file (extend_con) on its own. i still did not figure out if a server restart is needed. (the first time)
choose the path to put the file: (I preferre Daves way) app/myexten or what you like, making it 'app' specific and still distquishes to standard rails 'things'
if you are not lasy like me (i put it in app/ontrollers)
put the path you have choosen into
config/application.rb like (comments are there to find it)
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/app/controllers)
config.autoload_paths += %W(#{config.root}/app/myexten)
this one workes for me in all modes including "developer" and i did not need to put "my own" things in app/lib
It depends.
I tend to put library code used explicitly (e.g., instantiated, injected, etc. into app-level artifacts) into app/xxx where xxx signifies the "type" of thing, like decorators, services, etc.
Magic stuff tends to end up in lib, like monkey patches, architectural-level artifacts, and so on.
Code anywhere can be added to the autoload paths, required automatically by an initializer, etc.
Rails 4 comes with an internal directory for controllers called concerns. You could try using that.
app/controlls/concerns
If you have concerns/foo_bar.rb, you include it as follows:
class FooController < ApplicationController
include FooBar
end
Models also have their own concerns directory. I find this approach useful, and it can be applied to Rails 3. You just have to add the directories to your load paths.

Access Main App Helpers when overridings a Rails Engine View/Layout

I have created a simple Rails Engine to provide some general functionality(photo gallery) to an application. I want to be able to override the standard _header partial so that the menu for the gallery matches that of my main application. In my header view I call a helper that is part of application_helpers (main app), but I keep getting "undefined method" errors. From what I can tell the main app application_helpers are not being included (obviously) when I override the engines application layout or its partials.
So my question is, how do I override an engine view in the main application, and get access to the main application helper methods? I would still need access to the engine helpers as well as not to screw up the engine functionality.
Do I need to override the controllers as well? seem like a lot just to get some helpers.
Thanks
Rails 3.1.3
check out this blog post: http://www.candland.net/2012/04/17/rails-routes-used-in-an-isolated-engine/
The author adds a method_missing definition to the application helper in order to access the parent application's helpers.
/config/initializers/blogit.rb
module Blogit
module ApplicationHelper
def method_missing method, *args, &block
puts "LOOKING FOR ROUTES #{method}"
if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
if main_app.respond_to?(method)
main_app.send(method, *args)
else
super
end
else
super
end
end
def respond_to?(method)
if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
if main_app.respond_to?(method)
true
else
super
end
else
super
end
end
end
end
Try including the main app helper methods. For instance:
class MyEngineClass
include ApplicationHelper
#...
end
You may possibly need to require the file first, though I would expect Rails to correctly find it in this case.
Once ApplicationHelper is included, you should be able to directly use those helpers in the controller.
It also looks like you can call ClassName.helper("application") for a lot of Rails classes -- not sure if that will work here.
try creating a helper in your application with the same name of the helper in your engine in order to override engine helper methods.
I found this discussion particularly insightful. There are also some interesting ideas in the Rails Engine API docs under Isolated engine helpers.
Engines are supposed to be independent from the main app, that is why you can't access its helpers from the Engine.
However, there are hack-ish ways for giving your engine access to the helpers of the main app. This is how I did it:
# In the main app
# initializers/share_helpers_path_with_engine.rb
PhotoGallery::Engine.class_eval do
paths["app/helpers"] << File.join(File.dirname(__FILE__), '../..', 'app/helpers')
end
You need of course to change PhotoGallery to the actual name of your engine class.
Feel free to take a look at the Engines documentation (section about the paths): http://edgeapi.rubyonrails.org/classes/Rails/Engine.html
Disclaimer: I've only used this solution in Rails 3.2 engines.
If, in your engine you have a standard header partial vendor/gems/my_gallery_engine/app/views/application/_header.html.erb.
Then, override it in your main app by creating a customized partial app/views/application/_header.html.erb.
The override works because Rails' view template search path (by default) starts with the main apps' app/views directory, and then searches through engines' app/views in load order.
All of your main app's Helpers will be available in the partial.

Where to put custom classes in a Rails app so they are globally available?

I have a custom class located in lib and I want to create one instance of it that I can call anywhere in my Rails app--from controllers to rake tasks.
I can seem to do this with simple variables in an initializers file like this:
#foo = "bar"
and I can see #foo anywhere. How do I create an instance of my class so I can call it and its methods from anywhere?
In the lib directory: lib/some_thing.rb
Also see the comments in config/application.rb :
...
# Custom directories with classes and modules you want to be autoloadable.
...
It sounds to me that you're trying to create a singleton instance of your class in lib.
Have a look at Ruby's singleton module in the ruby standard library http://www.ruby-doc.org/stdlib/libdoc/singleton/rdoc/index.html
Then you can just always access it by
SomeClass.instance

Most appropriate way to generate directory of files from directory of template files with Rails and ERB?

My goal is to generate a directory of static html, javascript, and image files within my Rails (3) app, driven by ERB templates. For example, as a developer I might want to generate/update these files:
#{Rails.root}/public/products/baseball.html
#{Rails.root}/public/products/football.js
..from the following template files:
#{Rails.root}/product_templates/baseball.html.erb
#{Rails.root}/product_templates/football.js.erb
Ideally the templates would have access to my app's Rails environment (including URL helpers, view helpers, partials, etc.).
What's the latest and greatest way to accomplish this?
I experimented with a custom Rails generator, but found that I needed to write custom logic for skipping non-ERB files, substituting file names, etc. There must be a better way.
I'm not sure what you are trying to do exactly, that may help provide better answers, but here is some useful information:
You can call into erb directly, some information on that is here, which have probably already been doing:
http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
For the list of template files an easy Dir.glob should be able to help find the specific files easily and loop through them:
http://ruby-doc.org/core/classes/Dir.html#M000629
The tricky part I wouldn't know how to advise you on is getting access to the helpers and other things Rails provides. The helpers that you write are just modules, so you could mix those in, something similar might be possible with the built-in rails helpers.
This is interesting and related but doesn't directly answer your question, since its uses the Liquid templating engine instead of ERB, but otherwise, it does some of the static site generation you are talking about:
https://github.com/mojombo/jekyll
This is how I accomplished something similar. It accepts source and destination directories, wipes out the destination, then processes the source directory, either ERB-processing files and placing them in the destination or simply copying them (in the case of on-ERB files). It would need to be modified to handle recursively processing a directory.
I invoke it from a rake task like so:
DirectoryGenerator.new.generate(Rails.root.join('src'), Rails.root.join('public', 'dest'))
class DirectoryGenerator
include Rails.application.routes.url_helpers
include ActionView::Helpers::TagHelper
default_url_options[:host] = 'www.example.com'
def generate(source, destination)
FileUtils.rmtree(destination)
FileUtils.mkdir_p(destination)
Dir.glob(File.join(source, '*')).each do |path|
pathname = Pathname.new(path)
if pathname.extname == '.erb'
File.open(destination.join(pathname.basename.sub(/\.erb$/, '')), 'w') do |file|
file.puts(ERB.new(File.read(path)).result(binding))
end
else
FileUtils.cp(pathname, File.join(destination, pathname.basename))
end
end
end
end
Have you looked into Rails templates?
http://m.onkey.org/rails-templates for instance..
Not sure what you are getting at exactly.. are you trying to generate client sites by providing a few parameters.. that the end goal?

Resources