I want to implement friendly_id into existing model. Application uses russian gem, which handles new or hand-saved records well, but it doesn't seem to work when I update records from the command line.
User.find_each(&:save) (as friendly_id docs syggested) generate slugs like --<id>.
I used custom normalize method to provide transliterated slug:
def normalize_friendly_id(input)
Russian.transliterate input.to_s.mb_chars.downcase
end
but it definitely may miss some edge cases, and handles string differently from "normal" workflow. What I'm looking for is the way to reuse regular create/update flow and native behavior.
The best way to resolve this problem:
1) Add gem 'babosa' n your Gemfile
gem 'friendly_id'
gem 'babosa'
2) Owerride friendly_id's method in your model
def normalize_friendly_id(text)
text.to_slug.transliterate(:russian).normalize.to_s
end
Related
I have already read The Basics Of Creating Rails Plugins and several other articles, but I can't find how to supply a model with a gem.
Say, I want to make a gem for tagging (yes, I know about acts_as_taggable_on gem, I need different functionality). So, I want the model Tag to be bundled in the gem. I found no tutorial explaining that.
Of course I tried to reverse-engineer acts_as_taggable_on gem to understand how does it work, but it brought even more confusion: the tutorial I mentioned above says that I should have a dummy app in my gem, in order to test the gem. BUT, acts_as_taggable_on has no such dummy application! How how does it get tested, then?
About the model: ok, I see the file lib/acts_as_taggable_on/tag.rb that seems to be a Tag model:
module ActsAsTaggableOn
class Tag < ::ActiveRecord::Base
# ..........................
end
end
I see that file lib/acts-as-taggable-on.rb requires tag:
require "acts_as_taggable_on/tag"
So I've applied the same approach (assume my plugin is named dftags) :
I have added file lib/dftags/tag.rb:
module Dftags
class Tag < ::ActiveRecord::Base
# attr_accessible :title, :body
end
end
And my lib/dftags.rb looks like this:
module Dftags
end
require "dftags/tag"
I have specs tag_spec.rb:
require 'spec_helper'
describe Tag do
let(:tag) { Tag.new(name: "") }
it { should validate_presence_of :name }
end
And when I run bundle exec rspec spec/, I got error unitialized constant Tag (NameError).
It seems I missed something important. Plus, again, I have dummy app for testing, but acts_as_taggable_on doesn't; so, the testing approach should be different..
So, the questions:
How can I supply a model with gem?
How can I test my gem without dummy app?
Are there some advanced docs about writing rails gems? Actually I tried to check out one more famous gem: devise, but the ruby-fu and rails-fu of the authors is too strong for me to understand it. Where do people learn all of it?
How can I test my gem without dummy app?
The dummy app is only a helper that allows you to use your normal rails testing workflow when building a gem / plugin. You could run the tests without a dummy app but you would need a lot more manual work.
acts_as_taggable_on is pretty much active_record only with the exception of a single helper (as far as I can tell from a quick glance). The author therefore decided that the overhead of maintaining the dummy app was not worth the effort and is setting up active_record by hand. See here https://github.com/mbleigh/acts-as-taggable-on/blob/master/spec/spec_helper.rb#L24 how he establishes the connection to the database.
This code would not be necessary when using a dummy app as rails is taking care of it.
The same is true for the helper. Instead of using the test methods provided by rails he creates a new Class that includes the helper and uses an instance of this class to test it (h/acts-as-taggable-on/blob/master/spec/acts_as_taggable_on/tags_helper_spec.rb#L11).
I've tried a handful of captchas for Rails 3 and none tend to play nicely with Mongoid. I don't need anything too fancy just something to do a quick human check.
How do you guys get one working with Mongoid? Are there alternative solutions?
That's outside mongoid scope, but still applicable. Have a look at Negative Captcha:
Negative captchas create a form that has tasks that only bots can perform, but humans cannot. This has the exact same effect, with (anecdotally) a much lower false positive identification rate when compared with positive captchas. All of this comes without making humans go through any extra trouble to submit the form. It really is win-win.
You can use simple-captcha v1rtual's branch with mongo support. Simple and clean setup and usage:
Just add to your Gemfile as:
gem 'wolcanus-simple_captcha', :require => 'simple_captcha', :git => 'git://github.com/v1rtual/simple-captcha.git'
Run generator:
rails generate simple_captcha
For Controller Based, add the following line in the file "app/controllers/application.rb":
ApplicationController < ActionController::Base
include SimpleCaptcha::ControllerHelpers
end
In the view file within the form tags add this code:
<%= show_simple_captcha %>
and in the controller’s action authenticate it as
if simple_captcha_valid?
do this
else
do that
end
See the branch for more options: https://github.com/v1rtual/simple-captcha
Many solutions are available for rails 2 but none for rails 3.1 because the map object has been removed.
Any solution for this problem in the latest rails?
I have had to do this recently on a project. Luckily, it's simple to override the slug-generating method on a per-model basis.
please refer to
https://github.com/norman/friendly_id/blob/master/lib/friendly_id/slugged.rb#L113-116
and
https://github.com/norman/friendly_id/blob/master/lib/friendly_id/slugged.rb#L227-231
you should be able to define this on the model:
# Use default slug, but upper case and with underscores
def normalize_friendly_id(string)
super.upcase.gsub("-", ".")
end
Hope this helps.
Note: This method is available in FriendlyId 3.x as well. It's great for defining a custom regex for generating slug strings.
I'm using the Rails gem SimpleForm, but I think my question may be applicable to any gem.
https://github.com/plataformatec/simple_form
It has a lot of great features and customization, but I'm looking to go a bit further. For example, I really wish the markup generated had no default classes inserted into it, but I'd still like the ability to insert my own manually. I found that I could remove some of the classes by commenting out lines in the gem files. However this is outside of my project-- I would want a DRY solution that will stay with my project when I deploy to production, preferably without having to pack all of my gems.
I imagine this is a common situation that could apply to any gem, and I should be able to override any gem wholly or partially probably by adding customs files in my project that override the gem... but I'm not sure how.
Any help would be appreciated! Thanks.
Are you talking about monkey patching? Say your gem has a class in a file
# simple_form_gem/lib/some_file.rb
class A
def some_method
puts 'A'
end
end
If you want to change the output of #some_method then you can create an initializer file and do
# config/initializers/my_monkey_patch_for_simple_form_gem.rb
class A
def some_method
puts 'duck punching'
end
end
Your monkey patch will only affect A#some_method, and not other methods in A. Just make sure the output of your monkey patch won't break something else in the gem.
What is the recommended way to extend class behavior, via class_eval and modules (not by inheritance) if I want to extend a class buried in a Gem from a Rails 3 app?
An example is this:
I want to add the ability to create permalinks for tags and categories (through the ActsAsTaggableOn and ActsAsCategory gems).
They have defined Tag and Category models.
I want to basically do this:
Category.class_eval do
has_friendly_id :title
end
Tag.class_eval do
has_friendly_id :title
end
Even if there are other ways of adding this functionality that might be specific to the gem, what is the recommended way to add behavior to classes in a Rails 3 application like this?
I have a few other gems I've created that I want to do this to, such as a Configuration model and an Asset model. I would like to be able to add create an app/models/configuration.rb model class to my app, and it would act as if I just did class_eval.
Anyways, how is this supposed to work? I can't find anything that covers this from any of the current Rails 3 blogs/docs/gists.
I do this as follows, first add a file to config/initializers where you can require the files that contain your extensions:
# config/initializers/extensions.rb
require "#{Rails.root}/app/models/category.rb"
require "#{Rails.root}/app/models/tag.rb"
Then you can just re-open the classes and add whatever else you need:
# app/models/category.rb
class Category
has_friendly_id :title
end
Only downside is that the server has to be restarted for any changes to these files to take effect, not sure if there is a better way that would overcome that.
You can use rails_engine_decorator gem:
https://github.com/atd/rails_engine_decorators
Just add in your Gemfile:
gem 'rails_engine_decorator'
And user class_eval in your decorators:
/app/decorators/models/category_decorator.rb
/app/decorators/models/tag_decorator.rb
It works for me. I hope you find it useful!