• #16 楼 @Ryan 你的想法很有意思。既然本意就是“要 tag 必须和某个 article 关联”,为什么不直接用validates_presence_of :article呢?而是“跳过”这个概念,用更加“底层”的外键来验证。 至于accepts_nested_attributes_for,老实说,我也很少用..... -_-b 只是知道这个方法。有时候还是喜欢在 action 里预处理一下。这方面没有什么大问题,时间长了你自然也会知道的。:-) 我的本意只是希望给你一个建议:在发现一个问题的时候,稍微深挖一下。用 gem 当然是可行的方案(甚至也是最终的方案),但有可能就少学一些基础的东西了。 个人观点,仅供参考。:-)

  • #12 楼 @Rei @Ryan tag 这种常用的功能肯定有 gem,但我个人不是特别推荐直接给新手推荐 gem 来完成某个功能。因为这样很容易把问题掩盖起来。 自己实现虽然很有可能“笨拙”,但相当于自己对业务逻辑的做了分析和抽象。能学到很多东西。而很多 gem 都是"best practice"的结果。有些设定初学者根本无法理解。很容易把简单问题复杂化。出了问题也不知道到底是自己使用有问题,还是 gem 有 bug。 我自己在做一个项目的认证功能的时候,一开始考虑用 devise,但看了文档,发现功能实在“太强大”,我只是要一个非常简单的用户名密码的功能,却要设置很多东西(实际也不算多,但自己确实有点懒)。后来就自己写了几个 method,几个 helper 就完了。目前来说很“粗糙”,但是以后功能多了,复杂了,自然而然就会用 devise。我相信那时对其中的设置应该有更深的理解。 再说点题外话。我一个同事之前也想学 rails,我自己没什么“教学”的经验(本身就不是学计算机的,又不是在 it 公司工作,都是自己自学摸索的。),“自以为是”的给了他很多“经验”,以为帮他把一些坑填了他能更快学好。但现在发觉他虽然写个应用没什么问题(他都跳槽到软件公司去了),却还是会问我一些比较基础的东西,让我觉得很惊讶。我现在就在反省是不是应该在他学“游泳”的时候给他机会“呛几口水”。 以我个人的看法,楼主的问题本身就值得推敲。

    1. article_id设置在validates_presence_of里已经是比较“初级”的问题了(我没有恶意)。因为article都还没有保存的时候,不可能有这个值。如果知道validates_presence_of本身实际就是调用blank?,那#1 楼的方案应该也能想到。
    2. 而且实际上 rails 也可以直接在new的时候把关联的 model 设置好。accepts_nested_attributes_for不知道楼主有没有用过。 当然以上 2 点你做到了,不知道inverse_of,你还是会提这个问题,但是你对问题的理解肯定比现在的要好。 说了很多题外话....总之希望楼主有帮助吧。:-)
  • #6 楼 @Ryan

    1. 我记得自己当时做的时候只要加一边就可以了。查了 api,有这句for belongs_to associations has_many inverse associations are ignored.
    2. 你说是多对多,怎么会直接用has_many?如果是用中间一个 model(同时belongs_to tag 和 article)的话,那就应该在这个中间的 model 里加。你可以看看 api,上面的例子几乎和你的一样,他是 Post 和 tag。注意inverse_of是不支持through的。所以这种情况,你的validates应该也放在中间那个 model 里。
  • #4 楼 @Ryan 1 楼的验证 article 而不是 article_id 的方案是可行的。只是要在 belongs_to 加参数 inverse_of。 比如belongs_to :article, inverse_of: :tagsinverse_of的参数是 article 中关联 tag 的那个名字。比如has_many :tags中的tagshas_many也可以加。具体可以看 rails 的 api。 简单的说就是不加的话,在没有保存 article 之前,tag 是"看不到"关联的 article 的。因为必须靠 foreign_key,也就是 article_id 才能找到对应的 model。使用 inverse_of 就“类似于缓存”了关联的对象,即使没有保存(不使用 foreign_key)也能找到。 不知道解释清楚没有。 PS:“类似于缓存”这个说法只是我观察到的效果,没有看源代码的实现,所以不确定是不是真的这么做的。

  • @easymoo 请问现在还招吗? 申请页面有,但是 form 没了...之前想申请的,当时简历没弄好,难道那么不幸,刚准备好,就结束了?

  • 我印象中好像不是这样的。四种动作不是资源,url 才表示“资源”。就是这样:

    1. url 相当于唯一的资源 ID。比如/books/1
    2. 4 种 http 动作 (Verb) 是在说明要如何操作这个资源。就是同一个 url,但是使用不同类型的 http 请求,获得的效果是不同的。在 rails 里: get /books/1意思就是要“获取”这个资源。 put /books/1是要修改这个资源。实际是用 post 模拟的,修改的内容通过 post params 一起传过去。 delete /books/1就是要删除这个资源。也是 post 模拟的。 post /books是新建一个资源(因为是新的记录,所以没有 ID)。注意是“直接新建”,不是“要去新建”一个资源(那个是 get /books/new)。 总的效果类似数据库的CRUD4 个动作。
  • #14 楼 @woody1983 你没有理解我的意思。我不是说你修改user本身有什么问题。而是你现在处理的方法(绕开验证)不妥当,只是把问题藏起来,“看上去”没有问题了(程序能跑了)。 正像你自己说的,修改某些字段是一个常见的情况。那与其每次都绕过验证,不如把问题找出来,解决好。 我猜测问题是有虚拟的password属性,然后又在上面加了validation,所以当从数据库取出数据后,实例化的user还没有设置这个值,导致你save/update的时候无法通过验证。你可以试试在action里加上logger.debug(@user.errors.full_messages),然后看看后台输出是不是有password cannot be blank之类的信息。如果是这样#7 楼 的方法其实比你现在绕过验证要好很多。因为以后遇到其他需要修改某些字段的时候也一样可以避免这个问题。

  • 报密码不能为空可能是你有一个虚拟的 password 属性。比如你用了什么 auth 类的 gem,或者你自己加了一个attr_accessor :password。然后又有validates :password这样的验证。那么,当你是从数据库中取出记录User.find(params[:id])的时候,这个属性还是nil。你只修改 name 的话,就会报 invalid 了。 我觉得绕开验证不是好的方法。那个实际只是掩盖问题,不是解决问题。validates :password, :if => :new_record?更妥当。 另外,既然在 filter 里有了@user = User.find(params[:id]),action 里的第一句就多余了。 我就是搞不懂怎么会有 406。admin 修改用户后,没有format.html这样的语句是不是会导致 406?