Custom Views Scaffolding in Rails Engines - ruby-on-rails

I'm trying to get custom scaffolding working from my engine.
I followed some tutorial on customizing Rails 3.2 scaffolding in a normal Rails App and put my customized templates in the engines /lib/templates/erb/scaffold directory but they don't get picked up by the app that includes the engine. Any suggestions?
Update:
I also tried to override the Rails ScaffoldGenerator's source_path and tried some other paths to put my template in, like:
lib/rails/generators/erb/scaffold/templates

zarazan's answer got me most of the way there, but there are a couple of things wrong with it. Here's what worked for me:
class Engine < Rails::Engine
config.generators do |g|
g.templates.unshift File::expand_path('../../templates', __FILE__)
end
end
Note that this goes in the generators section, not app_generators, and that the path is slightly different.
Also, I think the correct path to store your templates is lib/templates/erb/scaffold, optionally replacing erb with whatever language you are using (like haml or slim.) I know this works for slim. The file names are {_form,edit,index,new,show}.html.erb.

In the file that you declare your engine use this command:
class Engine < Rails::Engine
config.app_generators do |g|
g.templates.unshift File::expand_path('../templates', __FILE__)
end
end
It should shift the preference of what template folder Rails uses by default.
Now just put the template files in lib/templates/erb/scaffold/template_name.erb
Where template_name is one of the following: _form.html.erb, edit.html.erb, index.html.erb, new.html.erb, show.html.erb
Once you include the gem you should be able to use the rails generate scaffold command as normal.
Here is an example of an engine that overrides the default scaffolding in rails:
https://github.com/brocktoncg/gemboree
This is where the template directory is located:
https://github.com/brocktoncg/gemboree/tree/master/lib/templates/erb/scaffold

Are you talking about a controller template? Than you are using the wrong directory. Save your template at
lib/templates/rails/scaffold_controller/controller.rb
Have a look at http://xyzpub.com/en/ruby-on-rails/3.2/templates.html for an example.

Related

Rails3/4 load path for class tweak

I'm trying to add a method to the DateTime class like so:
class DateTime
def ymd(sep = "/")
strftime("%Y#{sep}%m#{sep}%d")
end
end
I put this in #{config.root}/lib/datetime.rb and updated the autoload_path to include #{config.root}/lib (since that seems to go in and out of the conventional autoload path). That didn't work, so I also tried putting it in a random directory (#{config.root}/blah and added that path to the autoload_paths line in the config).
In all of the above cases, I'm only able to use the new method in the rails console if I require 'datetime' first, and I'm not able to use it in controllers or view templates no matter what I do.
So,
Should the file be called datetime.rb or date_time.rb? (I've tried both so far and neither are currently working)
Where should I be putting this file so I can use the new method in models, controllers and views?
Any idea why I can require it in the console, but it doesn't autoload there?
The app is currently running rails 3.2.21, but I'll switch to rails 4 at some point so answers for either version are appreciated.

Rails App to Angular: HAML + Rails Helpers

I'm trying to move my full-stack rails app over to Angular a page at a time. I'm using ui-router (https://github.com/angular-ui/ui-router) and angular-rails-templates (https://github.com/pitr/angular-rails-templates). I assumed the nghaml extension would allow me to continue to use rails helpers such as link_to, paths, etc. in my haml so just copied and pasted my haml page into the template; in an ideal world I would now be at a point where one page was being served client-side and every other page (including the ones it's linked to) were still being served server-side. Instead, I'm getting errors such as:
undefined local variable or method `dashboard_patients_path' for #<Object:0x007fc87865cff0>
and link_to, etc.
I thought this (angularjs with client side haml) would be a solid solution, specifically sharpper's response since it seemed directly applicable.
module CustomHamlEngine
class HamlTemplate < Tilt::HamlTemplate
def evaluate(scope, locals, &block)
scope.class_eval do
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include ActionView::Helpers
end
super
end
end
end
Rails.application.assets.register_engine '.haml', CustomHamlEngine::HamlTemplate
However, even after restarting the server, no dice.
Thoughts?
Got stuck with the same problem and found a solution after investigating angular-rails-templates, attentively reading their documentation and using the solution proposed by sharpper in angularjs with client side haml.
angular-rails-templates needs to recreate a mimeless version of the haml engine. So they extend the classes that are registered with Tilt instead of using the engines that were added to the asset pipelines. Therefore the new CustomHamlEngine that we create and register with the asset pipeline is never used by angular-rails-template. What we need to do instead is to register the engine with Tilt.
Create a file called angular_rails_templates.rb in the config/initializers folder and put this code in it.
# config/initializers/angular_rails_templates.rb
module CustomHamlEngine
class HamlTemplate < Tilt::HamlTemplate
def evaluate(scope, locals, &block)
scope.class_eval do
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include ActionView::Helpers
end
super
end
end
end
Tilt.register CustomHamlEngine::HamlTemplate, '.haml'
That will override the usual .haml engine with the one we just created. Angular-rails-templates will then process your haml file and it will support the rails helpers as well as the path helpers.
Don't forget to restart the server after including the file.

How to make Rails render slim templates instead of erb templates?

In my current project I used to use erb as the default view template, then I decided to switch to slim, so I used tools to convert all the .erb files to .slim files.
Now I have erb and slim files co-exist in the same folder, the problem is after I restarted the rails server, it still rendered the old .erb files, not the .slim files as I expected.
I have already put 'gem slim-rails' in my Gemfile and updated it, so what else should I do to let Rails choose these slim templates to render instead of the erb templates?
PS: Do I have to delete all the .erb files? Because I want to keep them as a study purpose.
i think you can just change the name of the files which contain those erb templates, so no need to delete them. So when you want to use erb, change to original name.
Make this configuration in config/application.rb
class Application < Rails::Application
...............................
config.generators do |g|
g.template_engine :slim
end
end
It seems that the answer to my last question is YES, I have to delete all the .erb templates, only in this way can Rails render the .slim templates as expected.
Though I still don't know why Rails prefer erb than slim when they both exist, could it be that e in erb priors to s in slim?

Extend a Model from a Rails Engine (not replace it)

I have a Rails app that uses a gem called ActsAsTaggableOnSteroids, which is a Rails Engine. Specifically, I'm using PavelNartov's fork of the gem. But nevermind that.
I need to add specific functionality to the Tag model, which is supplied by the engine.
But, according to my understanding of Rails engines and the magical loading functionality in Rails, if I put a file called "tag.rb" in my models directory, then it will completely replace the one from the Engine.
Ideally, I would be able to do something like:
class Tag < ActsAsTaggable::Tag
# my stuff
end
...but alas, that doesn't work because the model supplied by the engine is not namespaced.
So, I came up with this nightmare, which I put in app/models/tag.rb:
path = ActsAsTaggable::Engine.config.eager_load_paths.grep(/models/).first
require File.join(path, 'tag')
Tag.class_eval { include TagConcern }
But there has to be a better way! I feel like I'm missing something. I'd prefer not to add this strangeness to my app if possible.
Just require the file by looking up the path of the gem's model:
require File.join(Gem::Specification.find_by_name("bborn-acts_as_taggable_on_steroids").gem_dir, 'app/models/tag')
Tag.class_eval do
# ...
end

Override default scaffold generator in rails 3

I've created a generator for a controller in rails 3.
Now I want to use this generator as the default generator when using the scaffolding generator.
Is that possible?
The correct position for your customized controller file is lib/templates/rails/scaffold_controller/controller.rb
If you simply want to use your own controller template, you can just put it in lib/templates/rails/scaffold_controller/controller.rb
If you want to replace the scaffold_controller_generator code itself, for example, so that the controller scaffold generates additional class files. you can create lib/generators/rails/my_scaffold_controller/my_scaffold_controller_generator.rb with templates under lib/generators/rails/my_scaffold_controller/templates.
Remember to point rails at your new scaffold_controller in config/application.rb:
config.generators do |g|
g.scaffold_controller = "my_scaffold_controller"
end
For my_scaffold_controller_generator.rb you could copy from the railties gem under railties-3.x.x/lib/rails/generators/rails/scaffold_controller if you want to modify default behaviour, or inherit from it if you just want to add functionality:
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
module Rails
module Generators
class MyScaffoldControllerGenerator < ScaffoldControllerGenerator
source_root File.expand_path("../templates", __FILE__)
def new_funtionality
end
end
end
end
You can override the templates that Rails uses for its generators. In this instance, just place the file at lib/templates/scaffold_controller/controller.rb and modify it how you wish. The next time you run rails g scaffold [modelName] it will pick up this new controller template and use it.
This is covered in Section 6 of the Creating and Customizing Rails Generators official guide.
This seems to have changed slightly with Rails 4. You can see which template the generator will look for in the invoke line when the scaffold is generated, and your template folder name should match this:
rails generate scaffold blub
...
invoke responders_controller
If you're using rails g scaffold_controller blubs the location of the template should be:
lib/templates/rails/scaffold_controller/controller.rb
If you're using rails g scaffold blub the location of the template should be:
lib/templates/rails/responders_controller/controller.rb
If anyone is wondering why this isn't working in a default Rails 4 install, it's because jbuilder is inserting itself into the template path before the override location. I don't need jbuilder so I removed it, but I also reported an issue in Github. Hopefully it'll be fixed soon.

Resources