norman / friendly_id-globalize Goto Github PK
View Code? Open in Web Editor NEWGlobalize support for FriendlyId
License: MIT License
Globalize support for FriendlyId
License: MIT License
gem file:
gem 'friendly_id'
gem 'globalize'
gem 'friendly_id-globalize'
globalize migration:
class AddTranslationToPost < ActiveRecord::Migration[5.1]
def up
Post.create_translation_table!({
title: :string,
slug: :string,
sub_title: :string,
body: :text
}, {migrate_data: true})
end
def down
Post.drop_translation_table!
end
end
my model:
class Post < ApplicationRecord
translates :title,:slug ,:sub_title ,:body
extend FriendlyId
friendly_id :title, use: [:globalize, :history]
has_attached_file :image, styles: { post_index: "750x300", large: "600x600", medium: "300x300>", thumb: "100x100#{}>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
#def should_generate_new_friendly_id?
# title_changed?
#end
end
show.html.erb
<%= link_to I18n.with_locale(:es){post_path(@post, locale: 'es')} do %>
<%= image_tag('https://pilatesshopa.s3-eu-west-1.amazonaws.com/products/images/000/000/001/original/spain.png?1520005015', width: '23', height: '15.33', alt: 'English') %>
<% end %>
<%= link_to I18n.with_locale(:en){post_path(@post, locale: 'en')} do %>
<%= image_tag('https://pilatesshopa.s3-eu-west-1.amazonaws.com/posts/images/000/000/001/original/usa.png?1520004588', width: '23', height: '15.33', alt: 'English') %>
<% end %>
friendly_id-globalize:
class AddLocaleToFriendlyIdSlugs < ActiveRecord::Migration[5.1]
def change
add_column :friendly_id_slugs, :locale, :string, length: 2, null: :false, after: :scope
remove_index :friendly_id_slugs, [:slug, :sluggable_type]
add_index :friendly_id_slugs, [:slug, :sluggable_type, :locale], length: { slug: 140, sluggable_type: 50, locale: 2 }
remove_index :friendly_id_slugs, [:slug, :sluggable_type, :scope]
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope, :locale], length: { slug: 70, sluggable_type: 50, scope: 70, locale: 2 }, unique: true, name: :index_friendly_id_slugs_uniqueness
add_index :friendly_id_slugs, :locale
end
end
in Heroku everything is mixed up, I reset the database and it did not help.
thanks :)
It looks like FriendlyId's :history
option isn't supported. Would it be hard to implement? And any workaround would be valuable, thanks.
Hello !
Could you update the version on RubyGem ?
https://rubygems.org/gems/friendly_id-globalize/versions/1.0.0.alpha1
Gem version: friendly_id-globalize (~> 1.0.0.alpha3)
Ruby version: 2.3.0
Rails version: 5.1
I'm making use of the :history
plugin in a bunch of translatable models but also in a couple of non-translatable models like User
.
class User < ApplicationRecord
extend FriendlyId
friendly_id :full_name, use: [:slugged, :history]
...
end
For some reason my User model responds to :translations
which causes the friendly_id-globalize
to take over the history functionality. I needed to patch a few finder methods to make it work.
Instead of respond_to?(:translations)
it is better to use respond_to?(:translation_class)
.
I also found the need to override the create_slug
method to check if the model is making use of Globalize.
You might want to change the exists_by_friendly_id?(id)
method too because you are calling "super" on a non existing method. Because the Finder methods are included, they cannot be called with "super" and you must copy the method over from the original gem. You did it for create_slug
but forgot to do it for exists_by_friendly_id?(id)
People who are having the same issues can add this monkey patch to their initializers untill the issues are fixed:
module FriendlyId
module History
module FinderMethods
include ::FriendlyId::FinderMethods
def exists_by_friendly_id?(id)
if respond_to?(:translation_class)
joins(:slugs, :translations).where(translation_class.arel_table[friendly_id_config.query_field].eq(id)).exists? || joins(:slugs).where(slug_history_clause(id)).exists?
else
joins(:slugs).where(slug_history_clause(id)).exists?
end
end
def slug_history_clause(id)
if respond_to?(:translation_class)
Slug.arel_table[:sluggable_type].eq(base_class.to_s).and(Slug.arel_table[:slug].eq(id)).and(Slug.arel_table[:locale].eq(::Globalize.locale))
else
Slug.arel_table[:sluggable_type].eq(base_class.to_s).and(Slug.arel_table[:slug].eq(id))
end
end
end
def create_slug
if respond_to?(:translation_class)
translations.map(&:locale).each do |locale|
::Globalize.with_locale(locale) {super_create_slug(locale)}
end
else
super_create_slug(nil)
end
end
end
end
Using find() directly on my model generates a query which looks up the slug in the page_translations table:
Page.find('my-title')
SELECT FROM "pages" LEFT OUTER JOIN "page_translations" ...
-> #<Page id: 1 ...>
When I use find through a association, the translation table isn't being used. friendly_id uses the orginal table instead.
@site.pages.find('my-title')
SELECT "pages".* FROM "pages" WHERE "pages"."site_id" = $1 AND "pages"."slug" = 'my-title' LIMIT 1 [["site_id", 1]]
-> ActiveRecord::RecordNotFound
In Rails 3.2 (friendly_id 4.0.10, globalize 3.0.0) it works like this:
@site.pages.find('my-title')
SELECT "pages".* FROM "pages" WHERE "pages"."shop_id" = 1 AND "pages"."slug" = 'my-title' LIMIT 1
SELECT DISTINCT "pages".id, pages.position AS alias_0 FROM "pages" LEFT OUTER JOIN "page_translations" ...
SELECT "pages"."id" AS t0_r0, "pages"."title" AS t0_r1 ... FROM "pages" LEFT OUTER JOIN "page_translations"
-> #<Page id: 1 ...>
If you add a slug
index column on the translations table the whole thing blows up.
Hi, I use your gem with friendly-id and globalize (last versions) in a Rails 4.2.5 application. I need to update slug every time a user modify the attribute name.
Model :
class Project < ActiveRecord::Base
# Translations
TRANSLATED_FIELDS = [:name, :description, :full_description, :slug, :meta_desc, :meta_keys].freeze
translates *TRANSLATED_FIELDS, :fallbacks_for_empty_translations => true
# Friendly URL generation
extend FriendlyId
friendly_id :name, use: :globalize
validates_presence_of :name
end
When I use update action in my controller slug is not regenerated because slug is not nil in translations. I check the code and I realize that the method used to update slug is :
def should_generate_new_friendly_id?
translation_for(::Globalize.locale).send(friendly_id_config.slug_column).nil?
end
How can I manage to set slug attributes to nil?
I try :
before_validation :set_slug_nil_if_blank
def set_slug_nil_if_blank
self.slug = nil if slug.blank?
end
I go further and discover that the object instance in should_generate_new_friendly_id? seems to be the old one not the one which is updated.
Is there a classic way to do this?
I'm using slugged together with friendly_id-globalize on my model:
extend FriendlyId
friendly_id :title, :use => [:globalize, :slugged]
The initial generation of the slug works fine, but when I try to update my slugs when the title has changed with:
self.translations.each do |t|
t.slug = self.set_friendly_id t.title, t.locale
end
I get a:
NoMethodError: undefined method `set_friendly_id'
Is there a better, or at least a working way to handle slug-updates?! I've migrated from an earlier version of friendly_id where this approach worked, but as the docs haven't changed on I assumed that this should still be working...
Hello!
This issue is just a request for an update to the gem distributed at RubyGems.
In my project I use friendly_id-globalize
at 1.0.0.alpha3
. After upgrading to Rails 5.2 I am getting many of the following warning:
DEPRECATION WARNING: Dangerous query method (method whose arguments
are used as raw SQL) called with non-attribute argument(s):
"\"friendly_id_slugs\".id DESC".
Non-attribute arguments will be disallowed in Rails 6.0. This method should
not be called with user-provided values, such as request parameters or model
attributes. Known-safe values can be passed by wrapping them in Arel.sql().
I see this issue was already fixed in #26.
I'm happy to explicitly install the gem using the master ref instead of the RubyGems version in the meantime.
Thanks for your work on this gem and globalize
!
Hi there,
I've been scratching my head for the last few hours, looking for an answer but I can't find it anywhere.
My gem file:
# Use globalize for translating models
gem "globalize", github: "ncri/globalize" # for Rails 4.2
gem 'globalize-accessors', '~> 0.1.5'
# Use friendly_id for slugs
gem 'friendly_id', '~> 5.1.0'
gem 'friendly_id-globalize', '~> 1.0.0.alpha1'
Here's the situation:
So I assume friendly_id and globalize are properly configured.
However my problem is that I can't make a language switcher work using:
<% if I18n.locale != :en %>
<li>
<%= link_to t('menu.languages.short_en'), url_for(locale: 'en') %>
</li>
<% end %>
The route becomes en/pages/slug-fr (i.e. the language changes but not the slug).
I have activated config.use :finders in the initializer.
My page model:
translates :title, :slug, :blurb, :content, :seo_title, :seo_description, :seo_keywords
globalize_accessors :locales => [:en, :fr], :attributes => [:title, :slug, :blurb, :content, :seo_title, :seo_description, :seo_keywords]
extend FriendlyId
friendly_id :slug, :use => :globalize
validates :slug, presence: true, uniqueness: { case_sensitive: false }
So what do I need to do to have the proper path on my language switcher?
Ideally, I'd like this to work with any models, not just the Page model.
Thanks!
I am getting a lot of these warnings, after I upgraded a project to Rails 5.2.
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "\"friendly_id_slugs\".id DESC". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql(). (called from super_create_slug at /home/dev/.rvm/gems/ruby-2.4.4/bundler/gems/friendly_id-globalize-b5c1b8b442f6/lib/friendly_id/history.rb:130)
I've just tried to use friendly_id-globalize
with globalize
4.0.3 (rails-4-2 branch) and got an error because FriendlyId config was called before translates
. Even running something as simple as BlogPost.first
raised an error
[1] pry(main)> BlogPost.first
NoMethodError: undefined method `translated_attribute_names' for BlogPost (call 'BlogPost.connection' to establish a connection):Class
from /Users/lenart/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
Adding this to the readme might save someone else the frustration of figuring this out on their own.
If it's easier for you I can prepare the pull request.
This works with just friendly_id:
class Entry < ActiveRecord::Base
include FriendlyId
friendly_id :name, use: :slugged
end
entry = Entry.create! name: 'foo bar', slug: nil
# entry.slug == 'foo-bar'
however with globalize:
class Entry < ActiveRecord::Base
translates :name, :slug
include FriendlyId
friendly_id :name, use: [:slugged, :globalize]
end
entry = Entry.create! name: 'foo bar baz', slug: nil
# entry.slug == nil
only this works:
class Entry < ActiveRecord::Base
translates :name, :slug
include FriendlyId
friendly_id :name, use: [:slugged, :globalize]
end
entry = Entry.create! name: 'foo bar'
# entry.slug == 'foo-bar'
even setting should_generate_new_friendly_id?
to always return true doesn't change anything. It doesn't matter if it's a new entry or update on an existing one. As long as the 'slug' parameter exists with any content, it's not being overwritten (should_generate is called, slug does get generated, it's just that it has no effect).
I am using friendly_id
and friendly_id-globalize
gems in my Rails project.
Every time I update an article, the method title_changed?
is always nil even if I change it in the form which make slug never being updated.
It might be a gem bug.
For more details, I opened a StackOverflow post.
@parndt Hi ! Would it be possible to bump this gem (like alpha3) to use last commits and Friendly_id 5.2 ? Thanks !
I downloaded the gem and installed it, and when trying to run the rails g friendly_id_globalize
I get Could not find generator 'friendly_id_globalize'. Maybe you meant 'friendly_id', 'react_on_rails:base' or 'resource_route'
For globalized slugs, when both modules are enabled, scope and history, scope is not applied for new records, only for updated ones.
You can reproduce it creating two records with the same values excepting scoped data. Slug should be the same for both, but it doesn't. To let the same value, you have to modify translated slug with the same value of first record.
I think that the problem could be in the scope_for_slug_generator
method of the history module version provided for this gem. Only when record exists the scope is used to get the slug table relationship.
Changing the order of friendly_id_config.uses?(:scoped)
condition all works fine and slug is generated correctly:
@@ -109,12 +109,11 @@ method.
# used slug.
def scope_for_slug_generator
relation = super
- return relation if new_record?
- relation = relation.merge(Slug.where('sluggable_id <> ?', id))
if friendly_id_config.uses?(:scoped)
relation = relation.where(Slug.arel_table[:scope].eq(serialized_scope))
end
- relation
+ relation = relation.merge(Slug.where('sluggable_id <> ?', id)) unless new_record?
+ return relation
end
Even after using :scope
, friendly_id is generating a hashed version of the slug.
friendly_id (5.1.0)
rails (5.1.4)
ruby (2.1.4
class Board < ApplicationRecord
extend FriendlyId
friendly_id :name, use: [:scoped, :slugged, :history], scope: :company
belongs_to :company
has_many :posts
validates :slug, presence: true, uniqueness: { scope: :company }
end
> Board.create name: "Test Board", company: company
=> #<Board:0x007f8e192b53f0
id: 19,
company_id: 19,
name: "Test Board",
description: nil,
created_at: Fri, 06 Oct 2017 09:06:26 UTC +00:00,
updated_at: Fri, 06 Oct 2017 09:06:26 UTC +00:00,
slug: "test-board">
> Board.create name: "Test Board", company: company
=> #<Board:0x007f8e1bb4e820
id: 20,
company_id: 19,
name: "Test Board",
description: nil,
created_at: Fri, 06 Oct 2017 09:06:40 UTC +00:00,
updated_at: Fri, 06 Oct 2017 09:06:40 UTC +00:00,
slug: "test-board-1781b893-4c25-4875-acf4-0fb23ca09c52">
Am I missing something? I referred to: http://norman.github.io/friendly_id/file.Guide.html#Unique_Slugs_by_Scope
From the doc: Additionally, finds will fall back to the default locale:
Would be easy/reasonable to make this configurable?
For example, for SEO purposes one might not want www.example.com/it/english-slug
to be valid, but only www.example.com/it/italian-slug
and www.example.com/english-slug
.
thoughts?
Hi there,
Quick support question: how do I recreate my slugs?
I tried Model.find_each(&:save)
but it did not work.
Seems like this does not work on Ruby 3.0?
See here:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.