Rails Engines rendered View

2019-08-03 22:19发布

问题:

I have a rails engine I'm developing. This is my first one, besides the example in rails documentation, so I don't have a good ref on what works. It has a partial that i'm requiring the Application to render.

<%=render partial: 'my_engine/foo/bar'%>

That works fine. And i understand why i need to reference the partial through the engine name space.

But within the partial, i apparently have to use the name space as well. So when i render a photo

 <%= image_tag('my_engine/addphoto.jpg') %>

that is counter intuitive based on the documentation. Am I doing something wrong, or is just the way it is?

Okay thanks to Rich Peck I think I understand better. Let me enumerate so you can correct me if I'm still confused.

I was confused as to how the Namespace is generated for the engine. I was assuming that the structure generated the name space, and that when you were inside the engine, you would operate just as if you were in a normal app. And the namespace was automagic:).

But if I understand correctly the name space for the rails component is generated by encapsulating them in the :::: module EngineName which is taken care of by the generators, but if you're creating the file manually, then you need to add the encapsulation in the files. Since this was my first engine I didn't know that they were missing.

For the Asset pipeline the namespace is generated by the structure image/enginename/....

So even within the engine unless your inside the module, you have to honor the namespace EngineName::ModelName::Method.

The namespace isn't applied to the task file, doesn't seem to like being incapsulated in a module. But that is redundant anyway since the rake task already provide a namespace method.

Ala  namespace :db do

I was also surprised to find that you need to manually include the namespaced application controller in the namespaced controllers ala

require_dependency "enginename/application_controller"

but as Rich says, the engine is just a glorified module, so I guess it needs a little help now and then.

And of course the Javascript files are isolated because they're only loaded when one of the pages from the engine are loaded, and NOT when a partial from the engine is rendered. You can have the user of the engine include the javascript file in their application.js, but then they need to be namespaced manually to avoid confusing them with similar JS from other sources. There's a good blog on actually doing that by Kenneth Truyers that I'd bookmarked for a future exercise, maybe I'll need to get to it now.

lso the locales are not name spaced, so you need to do that yourself. Simple to add :engine_name to the locale file hierarchy ala de: :engine_name :variables I would recommend adding a prefix to the engine name like x so that you avoid getting your engine locales clobbered by a user using the same name as a variable. So xAdmin: would be better then Admin: since it's likely someone like me would use Admin: as a variable for an admin function:) and discover that all the localization in your engines suddenly disappeared.

Rich, am I closer

Now to extend my question,

I'm not sure that the initialization files are namespaced. Does a enginename.rb file in the apps initializers directory overwrite one with the same name in the engine's initializer directory? I assume if it's true we can just use a different name in the engine initializer since I think it there are no real associations to the file name, just bookkeeping.

Now how to extend a model in the app.

So to add columns to a apps model is it okay to do this in engine.rb (located in lib)
mattr_accessor :user_class mattr_accessor :user_table

in the engine_initializer.rb

    engine.user_class= 'User'
    engine.user_table='users'

then in the migration

add_column  Engine.user_table.to_sym, :attribute   
 add_index   Engine.user_table.to_sym, :attribute,   
        name: "index_#{Engine.user_table}_on_engine_attribute".to_sym

which seems to work okay

But how do we add methods to the model. I'm having the user add require 'engine/user_include.rb'

Is there a nice way to do that

回答1:

Modules & Classes

Am I doing something wrong, or is just the way it is?

You're not doing it wrong, but it's not "the way it is"... let me explain how it works

Rails engines are nothing more than glorified modules & Classes. When you create an engine (gem), it's essentially like creating a namespaced controller -'

#app/controllers/namespace/controller.rb
Class Namespace::Controller < ApplicationController
  ...
end

You have to remember Ruby on Rails is just a bunch of modules & classes. Obviously it's been created very well - but you have to realize that everything you do in Rails is involved with certain classes or modules in some way

And since engines are just a way to manage these modules & classes, you'll appreciate that an Engine is just a way to add extensibility with more of them.


Engines

module Blorgh
  class Engine < Rails::Engine
    ...
  end
end

Engines are designed to give you the ability to add standardized functionality to your system without intruding on your codebase (basically how gems work). Your question is whether you need to call your engine's name in paths etc:

<%= image_tag('my_engine/addphoto.jpg') %>

The bottom line is if you are bundling assets with your engine, how else is Rails going to access the files? Keeping the engine-based files separate from your other application means you will be able to bundle files specifically for the engine (they won't conflict).

This is the reason why the engines exist - they allow you to provide functionality without intruding on other parts of the application


Gems

Having recently worked on a gem, I can attest to the way of Engines

A rails gem is basically just an engine with some other files attached. So if you're including various controllers, models or assets with your gem - doesn't it make sense to make them unique to the engine (as to not conflict with the other parts of the app)?



回答2:

your codes will give you the expected output, rails offer different rendering option and tag attributes .

This reference will help you to update

1.layouts and rendering

2.partial redering