Rails activeRecord补丁和提交

时间:2014-08-29 20:26:05

标签: ruby-on-rails database activerecord

我正在使用rails处理标记的博客系统。现在它使用连接表,但我对性能有一些疑问。

现在,每次创建博客及其关联标记时,它都会向每个语句提交数据库。我认为更好的做法应该修补所有这些语句并仅提交数据库一次。在轨道上可以吗?

创建日志转储:

Started POST "/articles" for 127.0.0.1 at 2014-08-29 15:30:48 -0400
Processing by ArticlesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"K4rWQEh0810X2jMe/Z9pC/PN2WeOcO0F0TkjKUZTPec=", "title"=>"test27", "text"=>"ddddd", "tag"=>"a,k,g", "commit"=>"Submit"}
Unpermitted parameters: utf8, authenticity_token, tag, commit
   (0.9ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `articles` (`created_at`, `text`, `title`, `updated_at`) VALUES ('2014-08-29 19:30:48', 'ddddd', 'test27', '2014-08-29 19:30:48')
   (0.2ms)  COMMIT
  Tag Load (0.3ms)  SELECT  `tags`.* FROM `tags`  WHERE `tags`.`name` = 'a' LIMIT 1
   (0.2ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 1)
   (0.2ms)  COMMIT
  Tag Load (0.2ms)  SELECT  `tags`.* FROM `tags`  WHERE `tags`.`name` = 'k' LIMIT 1
   (0.1ms)  BEGIN
  SQL (0.2ms)  INSERT INTO `tags` (`name`) VALUES ('k')
   (0.1ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 17)
   (8.3ms)  COMMIT
  Tag Load (0.3ms)  SELECT  `tags`.* FROM `tags`  WHERE `tags`.`name` = 'g' LIMIT 1
   (0.1ms)  BEGIN
  SQL (0.2ms)  INSERT INTO `tags` (`name`) VALUES ('g')
   (0.1ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.4ms)  INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 18)
   (0.2ms)  COMMIT

模型设计:

class Article < ActiveRecord::Base
    has_and_belongs_to_many :tag
end

class Tag < ActiveRecord::Base
    has_and_belongs_to_many :article, :uniq => true
end

博客创建代码:

    def create
        @article = Article.new(article_params)
        tag_arr = params[:tag].split(',')

        if @article.save
          tag_arr.each do |name|
                tag = Tag.find_or_create_by(name: name) # create a new tag only if tag.name not exist
                @article.tag << tag
          end
          redirect_to @article
        else
          render 'new'
        end
    end

1 个答案:

答案 0 :(得分:1)

要在单个事务中保存文章和标记,请将操作包装在transaction块中。

def create
  @article = Article.new(article_params)
  tag_arr = params[:tag].split(',')

  Article.transaction do
    if @article.save
      tag_arr.each do |name|
        article.tags.find_or_create_by(name: name)
      end
    end
  end

  if @article.new_record?
    render 'new'
  else
    redirect_to @article
  end
end

这将导致SQL查询类似于:

(0.9ms)  BEGIN
SQL (0.3ms)  INSERT INTO `articles` (`created_at`, `text`, `title`, `updated_at`) VALUES ('2014-08-29 19:30:48', 'ddddd', 'test27', '2014-08-29 19:30:48')
Tag Load (0.3ms)  SELECT  `tags`.* FROM `tags`  WHERE `tags`.`name` = 'a' LIMIT 1
SQL (0.3ms)  INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 1)
Tag Load (0.2ms)  SELECT  `tags`.* FROM `tags`  WHERE `tags`.`name` = 'k' LIMIT 1
SQL (0.2ms)  INSERT INTO `tags` (`name`) VALUES ('k')
SQL (0.3ms)  INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 17)
Tag Load (0.3ms)  SELECT  `tags`.* FROM `tags`  WHERE `tags`.`name` = 'g' LIMIT 1
SQL (0.2ms)  INSERT INTO `tags` (`name`) VALUES ('g')
SQL (0.4ms)  INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 18)
(0.2ms)  COMMIT