Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Rails模型:您将如何创建一组预定义的属性?

Rails模型:您将如何创建一组预定义的属性?
EN

Stack Overflow用户
提问于 2011-06-30 06:40:42
回答 5查看 9.2K关注 0票数 39

我试图找出设计rails模型的最佳方法。就示例而言,假设我正在构建一个字符数据库,该数据库可能有几个不同的固定属性。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Character
- Morality (may be "Good" or "Evil")
- Genre (may be "Action", "Suspense", or "Western")
- Hair Color (may be "Blond", "Brown", or "Black")

..。诸若此类。

因此,对于字符模型,有几个属性,我想基本上有一个固定的列表,可能的选择。

我希望用户能够创建一个字符,我希望他们从每个可用选项中选择一个字符。我还想让用户使用这些属性中的每一个进行搜索.(即“给我看那些‘好’的人物,从‘悬疑’类型,并有‘棕色’的头发)。

我可以想出几种方法.

1:为每个属性创建一个字符串并验证有限的输入.

在这种情况下,我将在字符表上定义一个字符串列“道德”,然后有一个带有其中指定的选项的类常量,然后根据该类常量进行验证。

找到好的角色就像Character.where(:morality=>'Good')一样。

这很好,也很简单,缺点是如果我想给属性添加更多的细节,例如,有一个描述“好”和“邪恶”的页面,以及一个页面,用户可以在该页面中查看给定道德规范的所有字符。

2:为每个属性创建一个模型

在本例中,Character belongs_to Morality将有一个Morality模型和一个moralities表,其中包含两个记录:Morality id:1, name:Good等。

找到好的角色就像Morality.find_by_name('Good').characters.或Character.where(:morality=> Morality.find(1).

这很好,但这意味着您有几个表,这些表只保存少量预定义属性。

3:创建属性的STI模型

在本例中,我可以执行与#2相同的操作,除了创建一个通用的"CharacterAttributes“表,然后为"MoralityAttribute”和"GenreAttribute“等将其子类化。这只为多个属性创建了一个表,否则它似乎与idea #2类似。

所以,这是我能想到的解决这个问题的三种方法。

我的问题是,你将如何实现这一点,为什么?

你会使用上述的方法之一吗?如果是,哪一种?你会做些不同的事吗?我特别想听听您将采用的方法的性能考虑。我知道这是一个广泛的问题,谢谢你的意见。

编辑:,我正在添加250个Bounty (超过我名誉的10%!)在这个问题上,因为我真的需要对利弊/选项进行更深入的讨论。如果有人能给我一个很好的例子,说明他们采取哪种方法,以及为什么它会值+250,我会把它交给任何一个有建设性的人。

我真的在为我的应用程序的这个方面的设计而苦恼,现在是时候实现它了。提前感谢任何有帮助的讨论!!

最后注:

谢谢大家的周到和有趣的回答,所有这些都是好的,并对我很有帮助。最后(在赏金到期之前进来!)我真的很感激布莱克伯德07的回答。虽然每个人都提出了很好的建议,但对我个人来说,他的建议是最有用的。我以前并没有真正意识到枚举的概念,自从研究它之后,我发现它解决了我在应用程序中遇到的许多问题。我鼓励每一个发现这个问题的人阅读所有的答案,有很多很好的方法。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-07-20 10:53:06

简单地说,您是在问如何枚举ActiveRecord属性。关于在rails应用程序中使用枚举,有很多关于网络的讨论,例如这里这里这里等等。

我从未使用过许多用于枚举的宝石,,但是 活动的 听起来特别适合您的用例。它没有activerecord支持的属性集的缺点,因此对属性值的维护是小菜一碟。它甚至还附带表单帮助器,用于表单或简单表单(我认为它可以帮助您在字符搜索中进行属性选择)。

票数 11
EN

Stack Overflow用户

发布于 2011-07-14 10:52:19

我假设您将拥有更多的这些多选项属性,并希望保持整洁。

我建议将其存储在数据库 approach 中,如果您希望在运行时修改选择,则只使用,否则会很快影响性能;如果模型有三个这样的属性,则需要四个数据库调用,而不是一个。

将选项硬编码为验证是一种快速的方法,但它变成了乏味的来维护。您必须确保每个类似的验证器和下拉列表等都使用匹配值。如果列表变得很长,就会变得非常困难和麻烦。只有当你有2-5个真正不会改变的选择的时候,才是实用的,比如male, female, unspecified

推荐的是使用配置的YAML文件。这样,您就可以拥有一个整洁的文档供您选择。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# config/choices.yml

morality:
  - Good
  - Evil
genre:
  - Action
  - Suspense
  - Western
hair_color:
  - Blond
  - Brown
  - Black

然后,您可以将该文件作为Hash加载到常量中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# config/initializers/load_choices.rb

Choices = YAML.load_file("#{Rails.root}/config/choices.yml")

在你的模型中使用它;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# app/models/character.rb

class Character < ActiveRecord::Base
  validates_inclusion_of :morality, in: Choices['morality']
  validates_inclusion_of :genre, in: Choices['genre']
  # etc…
end

在视图中使用它们;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<%= select @character, :genre, Choices['genre'] %>

etc…

票数 25
EN

Stack Overflow用户

发布于 2011-06-30 07:14:31

如果这些属性中的任何一个更改都与代码中的更改紧密关联(即:当引入新的头发颜色时,将创建一个新的页面或实现一个新的操作),那么我会将它们添加为字符串哈希(选项1)。您可以将它们存储在字符模型中,作为与其他元数据的最终散列。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Character < ActiveRecord::Base
  MORALITY = {:good => ['Good' => 'Person is being good'], :evil => ['Evil' => 'Person is being Evil']}
  ...
end

Character.where(:morality => Character::MORALITY[:good][0])

编辑以添加注释中的代码:

给定Character::MORALITY = {:good => {:name => 'Good', :icon => 'good.png'}, ...

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- Character::MORALITY.each do |k,v| 
  = check_box_tag('morality', k.to_s)
  = image_tag(v[:icon], :title => v[:name])

= Character::MORALITY[@a_character.morality.to_sym][:name]
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6536527

复制
相关文章
C++11异步编程(std::async, std::future, std::packaged_task, std::promise)
       std::async是一个函数模板,会启动一个异步任务,最终返回一个std::future对象。在之前我们都是通过thread去创建一个子线程,但是如果我们要得到这个子线程所返回的结果,那么可能就需要用全局变量或者引用的方法来得到结果,这样或多或少都会不太方便,那么async这个函数就可以将得到的结果保存在future中,然后通过future来获取想要得到的结果。async比起thread来说可以对线程的创建又有了更好的控制,比如可以延迟创建。下面先介绍一下std::future, std::packaged_task, std::promise。
Ch_Zaqdt
2020/02/15
16.1K0
C++11 std::async
//g++ -std=c++11 -pthread -g std_future.cpp -o main // async example #include <iostream> // std::cout #include <future> // std::async, std::future // a non-optimized way of checking for prime numbers: bool is_prime (long int x) { std::co
awk
2018/08/23
4680
C++11 std::bind std::function 高级使用方法[通俗易懂]
Hello world ! sumFunc.Call<int>(1, 2, 3) : 6
全栈程序员站长
2022/02/04
9970
c++11:std::copy示例
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/84709909
10km
2019/05/25
1.7K0
std::function与std::bind
一、背景介绍: 函数指针始终不太灵活,它只能指向全局或静态函数,对于类成员函数、lambda表达式或其他可调用对象就无能为力了,因此,C++11推出了std::function与std::bind这两件大杀器,他们配合起来能够很好的替代函数指针。
灰子学技术
2022/01/18
9360
C++11:基于std::queue和std::mutex构建一个线程安全的队列
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/52067929
10km
2019/05/25
10.7K0
cmake+gcc解决extended initializer lists only available with -std=c++11 or -std=gnu++11
有时,我们需要一个结构体变量做为参数传递给函数,后面又不需要再用到这个结构体变量,所以如果专门定义一个变量,再将这个变量传递给函数就显得挺罗嗦。 就像下面这段代码,tmpStruct只是起到一个数据包装的作用,调用test()之后并不再用到,所以这个变量就显示有些多余 。
10km
2022/05/07
6350
理解std::move和std::forward
std::move和std::forward只是执行转换的函数(确切的说应该是函数模板)。std::move无条件的将它的参数转换成一个右值,而std::forward当特定的条件满足时,才会执行它的转换。这就是它们本来的样子.这样的解释产生了一些新问题,但是,基本上就是这么一回事。
杨永贞
2022/06/08
1.8K0
理解std::move和std::forward
std::jthread与std::thread区别
​std::jthread是C++20新引入的线程类,与 std::thread 类似,或者说,jthread是对thread进一步的封装,功能更强大​。
音视频牛哥
2022/04/03
1.3K0
std::atomic和std::mutex区别
​模板类std::atomic是C++11提供的原子操作类型,头文件 #include<atomic>。​在多线程调用下,利用std::atomic可实现数据结构的无锁设计。​​
音视频牛哥
2022/03/12
2.9K0
std::atomic和std::mutex区别
C++11 std::lock_guard 互斥锁
C++11中加入了线程,引入了多线程,也就伴随着一个多线程资源互斥的操作。对于锁的使用,有一个比较头疼的问题,就是在加锁后,容易忘记解锁,这样程序中可能会造成死锁。C++11中加入了lock_guard,这个的使用,可以让你不用关注解锁!
fensnote
2021/05/31
1.7K0
c++11:如何判断std::function对象相同?
我们知道std::function的实质就是个函数指针,但在c++11中std::function并没有实现操作符==(要到C++20才实现),所以我们无法使用==操作符来判断两个std::function对象是否相等,虽然我们明明知道它就是个指针。
10km
2020/04/08
1.8K0
<c++ 常用代码块> | std::string 与 std::wstring转化
#include <string>#include <locale>#include <codecvt>// convert string to wstringinline std::wstring to_wide_string(const std::string& input){std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;return converter.from_bytes(input);}// convert wstring t
IsEva
2022/12/05
9890
c++中的std::stod, stCPP程序说明std::stod():stof, std::stold
如果未执行转换,则会引发invalid_argument异常。如果读取的值超出双精度的可表示值范围,则会引发out_of_range异常。无效的 idx 会导致未定义的行为。
鲸落c
2022/12/14
3K0
想看懂WebRtc,你须知道的C++11新特性「lambda,std::function以及std:bind」
在本文中,我们来聊一下lambda表达式,闭包,std::function以及std::bind。
音视频_李超
2020/04/02
8430
std::function与std::bind使用总结
C++中函数指针的用途非常广泛,例如回调函数,接口类的设计等,但函数指针始终不太灵活,它只能指向全局或静态函数,对于类成员函数、lambda表达式或其他可调用对象就无能为力了,因此,C++11推出了std::function与std::bind这两件大杀器。
forrestlin
2019/07/29
11.4K0
诡异!std::bind in std::bind 编译失败
当时看了报错,简单的以为跟之前遇到的原因一样,随即提出了解决方案,怎奈,短短几分钟,就被无情打脸,啪啪啪😭。为了我那仅存的一点点自尊,赶紧看下原因,顺便把之前的问题也回顾下。
高性能架构探索
2023/06/13
7880
诡异!std::bind in std::bind 编译失败
C++11特性之std:call_once介绍
std:call_once是C++11引入的新特性,如需使用,只需要#include <mutex>即可,简单来说std:call_once的作用,确保函数或代码片段在多线程环境下,只需要执行一次,常用的场景如Init()操作或一些系统参数的获取等。
音视频牛哥
2022/05/12
2.3K0
C++11特性之std:call_once介绍
[C++11札记]: std::function
在C/C++中函数指针作为一种回调机制被广泛使用,但是函数指针在C++面向对象编程中有些不足,比如无法捕捉上下文。举个例子,使用对象的非静态成员函数作为函数指针就无法做到。
acoolgiser
2019/06/14
2.2K0
[C++11札记]: std::bind
在上一篇文章中,我们提到可调用对象(callable object),其中一种就是std::bind表达式。在这篇文章中,我们来谈谈std::bind表达式。
云水木石
2019/07/02
1.5K0

相似问题

带有std::weak_ptr的std::make_shared分配

28

std::make_shared()、std::weak_ptr和循环引用

37

std::std::weak_ptr向量和std::查找

11

std:bind和std::weak_ptr

13

成员函数中与本地静态std::map<std::string、std::weak_ptr>的访问冲突(C++11/STL)

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文