我的表格Slug与字段url是唯一的。
如果我创建@slug = Slug.url = "foo"
当我去保存时,如果“foo”的Slug.url已经存在,我想尝试一个“foo-1”的Slug.url如果它也存在,请尝试“foo-2”foo- 3,foo-4等等......直到找到一个不存在且可以在db中创建的值...在我的rails模型中用什么方法可以解决这个问题?
由于
更新
我的最新代码如下:
def set_url
self.url = self.title.parameterize
# Ensure the url is available
qUrl = self.url.split('-').shift
slugs = Slug.where("url like '#{qUrl}%'")
if slugs.exists?
c = slugs.count + 1
self.url = self.url + "-" + c.to_s
end
end
这段代码的问题在于qUrl正在拾取误报,任何时候标题都以“为什么”找到slugs这个词开头。在这里会有一些帮助,想出一些更可靠和优雅的东西。感谢
答案 0 :(得分:4)
我建议使用friendly_id gem。如果你看一下documentation in the slugged object,你会发现它有一个机制来处理唯一性,方法是将一个uuid附加到slug名称。
或者,有许多other slug generating gems可能更适合您的环境。
答案 1 :(得分:2)
以下是使用相同Slug模型的多个模型的Rails项目的完整设置说明,并在根目录配置了slug-URL路由:
使用friendly_id
的sequentially_slugged
模块,该模块在保存记录时(特别是在before_validation
回调期间生成来自唯一列的按顺序排序的段塞。
在新目录中启动新的Rails项目:
rails new .
将friendly_id
添加到Gemfile
(并在之后运行bundle install
):
gem 'friendly_id'
使用迁移生成slugs
表架构(之后运行rake db:migrate
),db/migrate/20170114211811_create_slugs.rb
:
class CreateSlugs < ActiveRecord::Migration
def change
create_table :slugs do |t|
t.string :url
t.string :title
end
add_index :slugs, :url, unique: true
add_reference :slugs, :item, polymorphic: true, index: true
end
end
使用Slug
,friendly_id
创建app/models/slug.rb
模型:
class Slug < ActiveRecord::Base
extend FriendlyId
friendly_id :title,
use: :sequentially_slugged,
slug_column: :url
belongs_to :item, polymorphic: true
end
您的用例要求单个根路由(例如/this-is-my-x
)。
config/routes.rb
:
Rails.application.routes.draw do
get ':url' => 'slugs#show'
end
要通过此单个Slug路线提供多个模型,您可以让Slug Controller将其render
操作委派给与所选Slug相关模型相对应的视图。
app/controllers/slugs_controller.rb
:
class SlugsController < ApplicationController
def show
@item = Slug.find_by(url: params[:url])
render "#{@item.item_type.pluralize.underscore}/show"
end
end
最后,开始使用多个模型中的单个Slug。
生成Article
架构+模型:
rails generate model article title:string
app/models/article.rb
:
class Article < ActiveRecord::Base
has_one :slug, as: :item
before_validation do
if slug.try(:title) != title
self.slug = Slug.create(title: title)
end
end
end
app/views/articles/show.html.erb
:
<h1>Articles#show</h1>
<p>Title is <%=@item.title%>, ID is <%=@item.id%></p>
然后为博客,标签等创建更多模型+视图
在rails console
中创建一些文章:
(1..10).each { Article.create title: 'foo' }
测试你的slug(运行rails server
,并访问localhost:3000/foo-7
):
Articles#show
Title is foo, ID is 7
全部完成!
答案 2 :(得分:1)
我的建议是使用before_save
回调(我没有尝试过代码,但在概念上回答):
Slug模型
before_save :check_and_generate_unique_slug
private
def check_and_generate_unique_slug
is_unique = Slug.where(url: self.url).count > 0 ? false : true
unless is_unique
#if say previous url was foo-1, self.url.last.to_i gives 1
new_url = "foo-#{self.url.last.to_i + 1}" #here it's foo-2
self.url = new_url
self.check_and_generate_unique_slug
else
self.url = new_url
end
end
注意即使最初的网址是&#34; foo&#34;,"foo".last.to_i
也会给0,下一个网址会是 foo - #{0 + 1} = foo-1
修改强>
更好的方式
def check_and_generate_unique_slug
urls = Slug.pluck(:url).uniq
#=> ["foo", "foo-1", "foo-3", "foo-2"]
latest_url_code = urls.map{|a| a.last.to_i}.uniq.sort.last
#=> urls.map{|a| a.last.to_i}.uniq.sort gives [0, 1, 2, 3]
#=> last will give 3
self.url = "foo-#{latest_url_code + 1}"
end
修改强>
如评论last could be a 2 digit
代码可以修改为:"foo-xxx".split("-").last.to_i
答案 3 :(得分:1)
试试这个
render() {
return (
{this.state.inputs.map(
(inputName, i) => <input type="text" name={inputName} key={i} />
)}
<button ... onClick= { this.addInput }></button>
);
}
function addInput() {
let temp = this.state.inputs.slice();
let size = this.state.inputs.length+1;
this.setState({inputs: temp.push("price"+length)});
}
答案 4 :(得分:1)
试试这个:
class Slug < ActiveRecord::Base
before_validation :set_slug, :on => :create
protected
def set_slug
tmp = "#{ title.downcase.gsub(/[^a-z0-9]+/i, '-') }"
i = 0
self.url = loop do
tmp.concat("-#{ i }") if i > 0
i += 1
break tmp unless Slug.exists?(url: tmp)
end
end
end
在控制台中试试。
tmp1 = Slug.create!(title: 'hello world')
tmp1.url #=> "hello-world"
tmp2 = Slug.create!(title: 'Hello World')
tmp2.url #=> "hello-world-1"