I'm trying to develop a Redmine Plugin, I started reading the documentation, and learning a lot of Ruby and a lot of Ruby on Rails. (I'm a PHP/Python/js guy)
Then I started looking through other plugins, and I found this code. I can't find enough information to fully understand how this line of code works:
Issue.send(:include, RedmineRequireIssueAllowedToChangeAssignee::Patches::IssuePatch)
I understand that inside IssuePatch are some things to override or add to Issue class.
Then I found this, explaining the use of send, and that confuses me, why not use just Issue.include?
The main question would be: where is this method include defined and what does it does?
UPDATE: related question
You can't just do include because it's a private method, so you use send which circumvents ruby visibility control. With send you can call any method, even private ones (as in this case).
where is this method include defined and what does it does?
It's defined as Module#include and, when invoked with a module as a parameter, it appends all instance methods of that module to the receiver (which is, in your case, Issue class). It's a very-very common idiom in Ruby.
Related
I am using Ruby on Rails 3.2.9 and Ruby 1.9.3-p125. After my previous question I ended up that I have an issue on metaprogramming a self-implemented acts_as_customizable plugin since the related code has side effects on other classes than that "acting as customizable".
To summarize the issue: the acts_as_customizable method stated for an Article model "internally" (through metaprogramming) adds a customize method to a Comment model and, in order to save time, Rails doesn't load all those classes on startup making the application to raise a NoMethodError - undefined method 'customize' for #<Comment:0x0...> until the Article class is loaded.
A proposed solution was to require_dependency 'article' in the Comment model, but I am looking for another way (maybe, better of the proposed one) to have the application to work as it is doing right now, but without any issue as-like that explained in this question. That is, I would like to keep a *short code** and the same behavior but using a more "appropriate" way to make things, maybe changing the loading process of classes or planning a big refactoring for the whole code, if necessary.
How should I handle this situation? What do you think about?
Update: After some study, I discovered that the problem arises only in development mode since the config.cache_classes is set to false making classes to be reloaded on every request.
Note: I want point out that metaprogramming is very usefull in my case and Article and Comment classes are highly related one to another in the aspect of my conception of "customization". So I would like to find a solution alleviating changes to the underling behavior.
* In my case, metaprogramming (even if it has side effects) makes me to avoid a lot of code statements.
I am using Ruby on Rails 3.0.7 and I have multiple resources that almost have the same behavior. That is, those almost have same model, controller and view codes and same database table columns definition.
So I would like to find a way to DRY those resources. I already implemented modules and mixins for those in order to share part of the code (as validation methods, callbacks, view files but not controller files that, anyway, have very similar code).
Now, how can I do to handle this common behavior? Should I use something that Ruby on Rails developers named as acts_as_something? What do you advice about?
I think you already did that, just name a method in your modules act_as_your_module_name and make sure your module extends from your Base Class, e.g. ActiveRecord::Base.extend act_as_your_module_name
http://www.cowboycoded.com/tag/acts_as/
When writing non-rails ruby project I often find myself in the position that I want to use certain parts of the Rails framework. This can be object extensions (like the String method camelize) or, as today, ActionDispatch::Assertions::SelectorAssertions, where I just want to add css_select to some of my tests.
I get pretty confused often over hyphenation/underscoring and often struggle to find out, what exactly I have to require. And I haven't found a system yet...
Is there a rule as to how to require a part of Rails if I know what module or class I want?
I suggest use active support library of rails. It has huge set of inbuilt methods which you can use in your ruby code. Just write in your ruby code.
require 'active_support'
http://as.rubyonrails.org/
I'm using YARD on my Rails project and was wondering how I would go about documenting inherited/runtime methods on a Rails model? For instance documenting the existence of a first_name attribute on a User model.
You can't do that, IMHO.
The trouble is that those methods don't really "exist"; They are "created on the fly" via method_missing hooks, the first time they are invoked, on runtime.
Other documentation generation systems have ways to declare "implicit" methods. For example NaturalDocs has a function keyword that allows you to create functions that only exist on the comments. I'm not familiar enough with YARD, but it seems it doesn't have a similar functionality.
Good luck!
Let's say I have a Rails app that gets most of it's functionality from a gem (for instance, a CMS).
If I now need to add some customisation (for instance, add a property to a user) what is the best practice way of doing this? If I customise the gem, then I will have issues with updating the gem in the future.
What is the best approach to take here?
This question is quite old, but I feel it could use a bit more fleshing out. It is true that you can monkeypatch rails (and ruby) at run-time. That means it's easy to reopen a class or module and inject new code. However, this is somewhat trickier in rails due to all the dynamic class loading and unloading that goes on development mode.
I won't go into details, but you really want to put your extensions into an initializer, or a gem, since they get reloaded between requests in dev mode. If you put the code into a plugin it won't get reloaded and you'll get very mysterious errors such as "A copy of XXX has been removed from the module tree but is still active!"
The easiest thing to do is throw the code into an initializer (e.g. config/initializers/user_extensions.rb). You can just use class_eval to inject the code.
User.class_eval do
... new code ...
end
One major drawback of ruby's extensibility is tracking down where code is coming from. You might want to add some kind of log message about the extensions being loaded, so people can track it down.
Rails.logger.info "\n~~~ Loading extensions to the User model from #{ __FILE__ }\n"
User.class_eval do
... new code ...
end
Further reading:
http://airbladesoftware.com/notes/monkey-patching-a-gem-in-rails-2-3
Ruby allows you to extend classes in runtime, so you can often hack in to a library without touching the source code. Otherwise I would suggest that you download the gem, create some hooks in the library and submit that back as a patch.
Update:
Note that these customisations are application specific
Yes. What I meant was to modify the generic api in a way, such that it is possible to customise per application. For example, by allowing the user to pass a block to certain methods etc.