使可重复使用的 Ruby on Rails 代码更加可重复使用的最合适的形式?

发布于 2024-12-07 18:16:14 字数 447 浏览 0 评论 0原文

我制作了很多 Rails 应用程序,并且似乎有很多方法可以使代码可重用。

我重用的内容包括:

css 文件、 初始化器, 视图/共享/部分 管理图像 应用程序助手 haml 视图模板 宝石 等等......

大约一年前,我曾经尝试将所有这些放入一个 gem 中,但它适得其反,主要是因为依赖关系的变化,以及我总是调整代码并添加到其中的事实。这作为 gem 来说并不好,因为要看到简单的更改发生,您必须编译/发布/安装 gem。所以宝石是不对的。

建议采用哪些方法来保持所有这些“个人”代码或多或少的模块化,以便我可以将其“放入”新的 Rails 项目中,并将其作为正常的 Rails 代码进行编辑(无需进行 gem 编译/发布)。

我想到的两个词是引擎和插件,但我真的不太了解它们是如何工作的。我还听说过(令人困惑的)“模板”,而不是视图类型。

您有什么建议。我很想弄清楚这个问题!

I make a lot of rails applications, and there seems to be lots of way to make code reusable.

Among the things I reuse are the following:

css files,
initializers,
views/shared/ partials
admin images
application helpers
haml view templates
gems
etc...

I once tried to put all of this into a gem about a year ago and it backfired terribly mostly because of changing dependencies, and the fact that I was always tweaking the code and adding to it. This is not good as a gem, because to see a simple change take place you have to compile/publish/install the gem. So the gem is not right.

What are recommended ways to keep all of this "personal" code more or less modular so I can "plop" it into a new rails project and edit it as normal rails code (no gem compiling / publishing).

The two words that come to mind are engines and plugins, but I really don't know much about how either of them work. I've also heard of (confusingly) "templates", not the view kind.

What are your suggestions. I'd love to get this figured out!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情未る 2024-12-14 18:16:14

您使用模板+引擎的思路是正确的。

模板非常适合一次性使用。它们允许您生成符合特定模板的应用程序,该模板为您的构建提供了良好的基础。您可以在这篇精彩指南中找到有关模板的更多信息。

我认为发动机是两者中更好的一个。它们允许您提供与模板相同的基础,但也允许您在以后扩展该基础。在一个引擎中你可以拥有你想要的一切。您可以通过运行以下命令来生成这些神话般的作品之一:

rails plugin new pixelearth_base --mountable

这将生成引擎的基础,然后您就可以拥有您想要的所有东西。

让我告诉你方法。

CSS 文件/图像

CSS 文件进入 app/assets,就像在 Rails 3.1 应用程序中一样,然后以相同的方式进行处理。您可以在资产管道指南中了解有关它们的更多信息。您可以像在应用程序中引用它们一样引用它们。当然,应用程序中与引擎中的资产名称相同的任何资产都将优先。

初始化程序

这些位于 config/initializers 中,就像应用程序一样(提示:这是一个带有引擎的运行主题)。它们的工作方式相同,并在配置指南的这一部分中进行了解释,虽然我想你已经知道这么多了。

共享视图

这些视图会进入引擎中的app/views/shared。应用程序中任何同名的文件都将优先于引擎中的文件。应用程序将能够无缝访问此目录中的任何文件,因为引擎的视图路径已添加到应用程序的视图路径中。

部分

同上。

Admin

您是否尝试过美妙的 rails_admin 引擎?也许那会适合你。如果没有,您可以将此功能构建到引擎中,就像在应用程序中一样。

助手

工作方式与其他事物大致相同。将它们添加到您的引擎中,您就可以开始使用了。尽管我对最后一点没有信心,但您可能必须在控制器顶部执行 helper SomeHelper 才能将它们包含在内。

Haml

使用如下行将其指定为引擎的 pixelearth_base.gemspec 文件中引擎的依赖项:

s.add_dependency 'haml', '3.1.3'

您的引擎(以及扩展后的应用程序)将能够在视图中使用 haml。

模板

我不确定你的意思,所以我会掩盖它。

Gems

共享 gem 依赖项应在 pixelearth_base.gemspec 中指定,就像 haml 示例一样。


包含引擎

现在,您需要将此引擎包含到您的应用程序中,但您不想一直经历更新 gem 的痛苦。我认为最好的方法是将 gem 推送到 GitHub,然后在应用程序的 Gemfile 中指定如下行:

gem 'pixelearth_base', :git => "git://github.com/pixelearth/pixelearth_base"

每当您更新此 gem 并将新更改推送到 GitHub 时,您都需要运行 bundle update Pixelearth_base 以使用最新版本更新您的应用程序。每次运行bundle update时,它都会被锁定到该特定版本。在您再次运行 bundle update ... 之前,对引擎的任何进一步更改都不会得到确认。


安装引擎

您在 IRC 中询问的最后一件事是安装。如果您碰巧选择在引擎中共享功能(即控制器等),那么您需要在应用程序中安装引擎。这非常简单,可以通过将此行放入您的 config/routes.rb 中来完成:

mount PixelEarth::Engine, :at => "pixelearth"

PixelEarth::Engine 类在您的引擎中的 lib 中定义/pixel_earth/engine.rb 并通过继承 Rails::Engine 提供所需的所有功能。您应用程序中的任何功能现在都可以在应用程序中的 /pixelearth 中使用。

You're on the right line of thinking with templates + engines.

Templates are great for one-time use. They allow you to generate an application that conforms to a specific, um, template, which provides an excellent base for you to build on top of. You can find more information about templates in this wonderful guide.

Engines, I think, are the better of the two. They allow you to provide that same base that templates would, but then also allow you to expand on that base for later. Within an engine you can have all the things you want. You can generate one of these fabulous creations by running this command:

rails plugin new pixelearth_base --mountable

This will generate the base of an engine, which then you can have all the things you wanted.

Let me show you the ways.

CSS files / images

CSS files go into app/assets, just like in a Rails 3.1 application, and are then processed the same way. You can read more about them in the Asset Pipeline guide. You can reference them exactly the same way you would reference them if they were inside your application. Of course, any asset inside your application named identically to one inside your engine will take precedence.

Initializers

These go in config/initializers, just like an application (hint: this is a running theme with engines). They work the same way and are explained in this section of the Configuring Guide, although I reckon you know that much already.

Shared views

These go into app/views/shared in your engine. Any file in your application named identically will take precedence over the file in the engine. The application will be able to seamlessly access any file in this directory, since engines have their view paths added to the application's.

Partials

Ditto.

Admin

Have you tried the wonderful rails_admin engine for this? Perhaps that would suit you. If not, you can build this functionality into your engine just as you would in an application.

Helpers

Work in much the same way as everything else. Add them to your engine and you'll be good to go. Although I am not confident in that last point, you may have to do helper SomeHelper at the top of the controller to get them included.

Haml

Specify this as a dependency of the engine in the engine's pixelearth_base.gemspec file using a line like this:

s.add_dependency 'haml', '3.1.3'

Your engine (and by extension, your application) would be able to use haml in views.

Templates

I am not sure what you mean by this, so I am going to gloss over it.

Gems

Shared gem dependencies should be specified in the pixelearth_base.gemspec just like the haml example.


Including the engine

Now, you're going to need to include this engine into your application but you don't want to go through the pain of updating a gem all the time. I reckon the best way to do this is to push the gem to GitHub and then specify a line like this inside your application's Gemfile:

gem 'pixelearth_base', :git => "git://github.com/pixelearth/pixelearth_base"

Whenever you update this gem and push new changes to GitHub, you will need to run bundle update pixelearth_base to update your application with the latest version. Each time you run bundle update it will be locked to that specific version. Any further changes to the engine won't be acknowledged until you run bundle update ... again.


Mounting the engine

One final thing which you asked about in IRC is mounting. If you happen to go the route of having shared functionality in your engine (i.e. controllers and so on) then you'll need to mount your engine within your application. This is very easy and can be done by putting this line in your config/routes.rb:

mount PixelEarth::Engine, :at => "pixelearth"

The PixelEarth::Engine class is defined in your engine at lib/pixel_earth/engine.rb and provides all the functionality it needs by inheriting from Rails::Engine. Any functionality from your application will now be available at /pixelearth in your application.

执笏见 2024-12-14 18:16:14

这取决于文件,如果您愿意,我可以为您分解答案。但我的一般建议是保持代码小、轻量级并且专为一项任务而设计。做到这一点的一个好方法是确定您编写的代码是否正交。维基百科在计算机科学范围内将其定义为:

正交性是一种系统设计属性,有助于提高可行性和
复杂设计的紧凑性。正交性保证
修改系统组件产生的技术效果
既不会产生也不会将副作用传播到其他组件
系统。由组件组成的系统的紧急行为
应严格受其逻辑和形式定义的控制
不是由不良整合产生的副作用,即
模块和接口的非正交设计。正交性降低
测试和开发时间,因为验证设计更容易
既不会引起副作用也不依赖它们。

至于限制代码的大小,您可以根据自己的个人判断来决定何时何地委托方法和类。不过,我想记住关注点分离单一责任原则在将我面临的问题分解为更小的部分时。

然而,你不能只写出好的代码然后就这样,你需要有一种好的方法来分发你的代码。我的 LAN 上有一个开发服务器,它托管许多私有 Git 存储库,但是您可以使用任何 VCS 或 DVCS 来组织代码。然后,当我需要更新文件并进行更改时,我可以使用它来保持我的项目从服务器获取文件的最新版本,并且如果我正在处理的项目的需求发生变化,我可以随时进行分支。使用 Git,我始终将代码置于版本控制中,因此我使用 子模块 来让我保持最新版本的代码方便且保持最新。

如果您需要更多信息或者您不使用 Git,请告诉我,我可以在您熟悉的 VCS 上寻找类似的功能。另外我想指出,这是一个很好的问题,有很多要点,我很高兴你问我,因为我记得我曾为此苦苦挣扎,而且我确信其他人也在解决同样的问题。

It depends on the file, if you want I can break an answer down for you. But my general advice is to keep your code small, lightweight and designed for one task. A good way of doing this is determining if the code you write is orthogonal. Wikipedia defines it in a computer science scope as this:

Orthogonality is a system design property facilitating feasibility and
compactness of complex designs. Orthogonality guarantees that
modifying the technical effect produced by a component of a system
neither creates nor propagates side effects to other components of the
system. The emergent behavior of a system consisting of components
should be controlled strictly by formal definitions of its logic and
not by side effects resulting from poor integration, i.e.
non-orthogonal design of modules and interfaces. Orthogonality reduces
testing and development time because it is easier to verify designs
that neither cause side effects nor depend on them.

As far as constraining the size of your code you can leave that up to your own personal judgement on when and where you delegate methods and classes. However I like to keep in mind the separation of concerns and the single responsibility principle when working on breaking up the issues I face into smaller parts.

However you cant just write good code and leave it at that, you need to have a good way of distributing your code. I have a development server on my LAN that hosts many private Git repositories however you can use any VCS or DVCS to keep your code organized. I can then use this to keep my projects sourcing the latest versions of the files from the server when I need to update them and make changes and I can always branch if my requirements change for the project I'm working on. With Git I always have my code in version control so I use submodules to let me keep the latest version of the code handy and up to date.

Let me know if you want more information or if you dont use Git I can look for similar features on a VCS you are familiar with. Also I'd just like to note that this is a good question that has a lot of points and I'm glad you asked since I remember struggling with this and I'm sure others are tackling the same problem as well.

风轻花落早 2024-12-14 18:16:14

当我为我的应用程序编写我认为可以在其他项目中重用的软件时,我将其编写为自己的插件。

我从我已经使用的插件之一复制插件目录模型。

When I write sw for my app that I feel could be re-usable in other projects, I write it as its own plugin.

I copy the plugin dir model from one of the plugins that I'm already using.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文