Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 使用rails ActiveRecord结构化_Ruby On Rails_Ruby_Activerecord - Fatal编程技术网

Ruby on rails 使用rails ActiveRecord结构化

Ruby on rails 使用rails ActiveRecord结构化,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,我实际上是Ruby和Rails框架的初学者,这就是为什么我决定在做一些打破框架惯例的事情之前寻求帮助的原因 我有一个相当扎实的OO编程背景,我对初学者->中级SQL查询非常熟悉。然而,我一直很难理解Rails提供的ActiveRecord类。我的直觉是完全废弃ActiveRecord类,手工编写自己的SQL查询并将它们封装在模型中。然而,我知道ActiveRecords是Rails框架中相当重要的一部分,避免使用它们只会让我将来感到痛苦 下面是我的MySQL模式(稍后我将编写一个Rails迁移)

我实际上是Ruby和Rails框架的初学者,这就是为什么我决定在做一些打破框架惯例的事情之前寻求帮助的原因

我有一个相当扎实的
OO
编程背景,我对初学者->中级SQL查询非常熟悉。然而,我一直很难理解Rails提供的
ActiveRecord
类。我的直觉是完全废弃ActiveRecord类,手工编写自己的SQL查询并将它们封装在模型中。然而,我知道ActiveRecords是Rails框架中相当重要的一部分,避免使用它们只会让我将来感到痛苦

下面是我的
MySQL
模式(稍后我将编写一个
Rails迁移
)。我会尽量让这个问题尽可能简洁,但我可能需要深入一些背景知识来解释为什么我会像现在这样对模式进行建模。我不太喜欢它,所以如果人们对它的结构有更好的想法那就太好了

-- Users table is a minimalized version of what it probably will be, but contains all pertinent information
CREATE TABLE IF NOT EXISTS users (
    id          INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name        VARCHAR(20) UNIQUE NOT NULL
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS hashtags (
    id          INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    tag         VARCHAR(30) UNIQUE NOT NULL
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS content_mentions (
    content_id  INT UNSIGNED NOT NULL,
    user_id     INT UNSIGNED NOT NULL, 
    INDEX(content_id),
    FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS content_hashtags (
    content_id  INT UNSIGNED NOT NULL,
    hashtag_id  INT UNSIGNED NOT NULL,
    INDEX(content_id),
    FOREIGN KEY(hashtag_id) REFERENCES hashtags(id) ON DELETE CASCADE
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS content_comments (
    id          INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    user_id     INT UNSIGNED NOT NULL,
    content_id  INT UNSIGNED NOT NULL,
    text_body   VARCHAR(1000) NOT NULL,
    date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
    INDEX(content_id)
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS polls (
    id          INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    user_id     INT UNSIGNED NOT NULL,
    question    VARCHAR(100) NOT NULL,
    text_body   VARCHAR(1000) NOT NULL,
    date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS poll_options (
    id          INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    poll_id     INT UNSIGNED NOT NULL,
    content     VARCHAR(150) NOT NULL,
    active      VARCHAR(1) NOT NULL DEFAULT 'Y',
    FOREIGN KEY(poll_id) REFERENCES polls(id) ON DELETE CASCADE
) Engine=InnoDB;

CREATE TABLE IF NOT EXISTS poll_answers (
    poll_option_id  INT UNSIGNED NOT NULL,
    user_id     INT UNSIGNED NOT NULL,
    FOREIGN KEY(poll_option_id) REFERENCES poll_options(id) ON DELETE CASCADE,
    FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
    PRIMARY KEY(poll_option_id,user_id)
) Engine=InnoDB;
如模式所示,这是一个非常基本的web轮询应用程序。每个民意测验都有多个选项,每个选项都可以有不同用户的多个答案。现在,奇怪的部分可能是
content.*
表。我能解释这一点的最好方法可能是将其描述为一个
抽象表。我以前从未真正做过这样的事情,通常关系是在两个或多个显式表之间,我会根据需要添加外键。然而,在这种情况下,我可能会得到多种不同类型的
内容
,所有这些内容都需要hashtagg/提及/评论。我事先不知道
content\u id
指的是什么表(代码将适当地处理它接收到的数据),所以我现在只对该列进行了
索引。
我需要在某个阶段调整
content.*
表以添加
type
列,因为一旦出现多个
content
表,如果两个表都使用自动递增主键,则可能会有重复的
content\u id
条目,我认为这超出了问题的范围

关于ActiveRecord类的结构。第一部分是处理提及/hashtags的解析。我编写了一个抽象
Content
类来处理表的“抽象”部分。它是这样的(为了简洁起见,一些解析已经被删除)

所以我想我的问题如下:

class Poll < Content
    has_many :poll_options;
    has_many :poll_answers, { :through => :poll_options }

    attr_accessible :user_id, :question;
    validates :text_body, :presence => true, :length => { :maximum => 1000 };
end

class PollOption < ActiveRecord::Base
    belongs_to :poll;
    has_many :poll_answers;

    attr_accessible :content, :active, :poll_id;
end

class PollAnswer < ActiveRecord::Base
    belongs_to :poll_option;
    belongs_to :user;

    attr_accessible :user_id, :poll_option_id;
end

class User < ActiveRecord::Base
    attr_accessible :name;

    validates :name, :presence => true, :length => { :maximum => 20 };
end

class Hashtag < ActiveRecord::Base
    attr_accessible :tag;

        validates :tag, :presence => true, :length => { :maximum => 30 };
end

# Join table for content->users
class ContentMention < ActiveRecord::Base
    belongs_to :user;
    belongs_to :content, { :polymorphic => true };

    attr_accessible :content_id, :user_id;
end

# Join table for content->hashtags
class ContentHashtag < ActiveRecord::Base
    belongs_to :hashtag;
    belongs_to :content, { :polymorphic => true };

    attr_accessible :content_id, :hashtag_id;
end
  • 模式本身是否正确(即,它是否非常低效,并且设计得很差,无法与rails一起使用?(如果是这样,关于如何纠正它的建议将非常好)
  • 保存前后的
    是否是解析和更新关联的正确位置
  • 我的ActiveRecords是否基于当前架构结构正确设置?(具体来说,我不确定是否正确使用了
    polymorphic
    属性)
  • 如何向
    轮询
    实例添加选项/答案,而不重新保存轮询的整个内容(从而触发对内容的另一个冗余解析),同时仍保留
    OOP
    方法?(即,选项/答案通过
    轮询
    模型中的公共API创建)

  • 如果一个对
    Rails
    Ruby
    ActiveRecord
    非常熟悉的人能给我一份他们将如何实现这一基本功能的快速副本,那就太好了。正如我说的,我以前从未使用过
    ActiveRecord
    类,所以我甚至不确定这个简单代码将包含多少原始SQL查询我已经在一个
    save()
    调用中触发。

    这是一个由两部分组成的railscast,涵盖了实现轮询/调查应用程序的各个方面。它涵盖了大多数与模型相关的疑问

    我将在赋值过程中通过覆盖
    text\u body
    的setter来创建依赖对象

    例如:

    而不是:

    belongs_to :content, { :polymorphic => true };
    
  • 对于代码重用,请使用模块而不是继承

  • 对于
  • 了解阵列上的
    映射
    减少
    (即
    注入
    )函数


  • 我认为这个问题有点太大了——它几乎要求你的应用程序提供咨询服务。我想说的是,如果你从Rails开始,就去尝试一下,当你犯了错误并学习了之后,你可以回去逐步改进。不过,有一个技巧是在保存后使用
    ,而不是在保存前后使用
    ld
    。我知道这是一个相当大的问题,但我要问的只是少量的代码,大部分只是关于在嵌套联接表中正确使用ActiveRecords的一些建议,避免了冗余更新记录的需要。应用程序的hashtag/提及/注释端与问题无关(关于构造“抽象”表格的一般问题除外),所以本质上,它只是问如何使用ActiveRecords实现
    轮询
    ,而不是真正的“大”。至于
    after_save
    方法,我找不到关于是否可以在其中回滚的清晰文档。你可能是对的,这是一个微不足道的代码量,但理解上下文是对于能够提供这些琐碎代码的人来说,这是一项巨大的时间投资。如果可能,最好将其分解为更小的问题。理解Rails是非常重要的,任何熟悉Rails的人都应该已经熟悉活动记录的上下文和应用程序,因此这将是一项非常重要的工作etty对他们直截了当。它基本上只有3个表…如果你知道你在做什么,就不会有很多工作。我可以在大约10-20分钟内手动完成SQL,但我宁愿使用Ac
    def text_body=(val)
      write_attribute(:text_body, val).tap do |v|
        append_new_tags_and_mentions
      end
    end
    
    def append_new_tags_and_mentions
      tag_list, mention_list = extract_tags_and_mentions
      new_mentions = mention_list - mentions.where(name => mention_list).pluck(:name)    
      mentions.concat(*new_mentions) if new_mentions.present?   
      new_tags = tag_list - hashtags.where(tag => tag_list).pluck(:tag)
      hashtags.concat(*new_tags) if new_tags.present?
    end
    
    def extract_tags_and_mentions
      tag_list = []
      mention_list = []
      text_body.scan(ENTITY_PATTERN) do |boundary, token, value|
        if token == "@"
          mention_list << value
        else
          tag_list << value
        end
      end
      [tag_list, mention_list]
    end
    
    belongs_to :content, :polymorphic => true
    
    belongs_to :content, { :polymorphic => true };