Jquery Validation Plugin and Select2

Jquery Validation Plugin是非常棒的验证插件,select2也是一款很不错的select插件,让select更加强大与美观。

Jquery Validation Plugin会默认忽视hidden的元素,而select2会把真正的select隐藏,而用自己的元素进行包裹,这时,select2就无法验证了。

解决方案是:在初始化validator时,设置ignore参数

1
2
3
4
5
6
7
8
9
$form.validate
  rules:
    'user[channel]':
      required: true
  messages:
    'user[channel]':
      required: '请选择频道'
  #select2把真正的select隐藏了,而jquery validator会忽略需要特殊处理
  ignore: 'input[type=hidden]'
Comments

Rails ActiveSupport::Concern Object Doesn’t Support#inspect

这篇博客记录使用ActiveSupport::Concern对业务进行抽象时,遇到的Object doesn’t support#inspect问题.

背景

树形数据结构在系统中越来越多,而他的很多特性是可以复用的,如果对每一个model都定义相同的方法,声明相同的asscoiation肯定是不科学,于是打算将其抽取出来.

第一个方案打算使用继承,使用通用类继承ActiveRecord::Base 然后其他的树形类再继承这个通用类

1
2
3
4
  TreeBase < ActiveRecord::Base
  end
  GrammarTree < TreeBase
  end

但是这样会报错,提示在数据库中找不到tree_bases这张表,这是肯定的,于是根据网上的方法,把TreeBase设置成没有表与其对应的虚类,但是Rails还是不吃这一套.

1
2
3
4
  TreeBase < ActiveRecord::Base
    self.absract_class = true
    @columns = []
  end

于是打算采用module的方案,Rails4重大设计决策:“胖”Model用ActiveSupport::Concern瘦身, 那就先采用这个做法试验一下.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
module TreeBase
  extend ActiveSupport::Concern

  included do
    attr_accessible :p_id, :_name, :order_idx, :level, :overall_idx
    belongs_to :parent, class_name: self.class.name, foreign_key: "p_id"
    has_many :children, class_name: self.class.name, foreign_key: "p_id", dependent: :restrict, order: :order_idx
    validates :node_name, presence: true

    default_value_for :level do
      parent.nil? ? 0 : (.parent.level + 1)
    end
    default_value_for :order_idx do
      if parent.nil?
        (self.class.where(p_id: nil).maximum(:order_idx) || 0) + 1
      else
        (parent.children.maximum(:order_idx) || 0) + 1
      end
    end
    default_value_for :overall_idx do
      self.compute_overall_idx
    end

    after_save :reset_index
  end

  module ClassMethods
  end

  module InstanceMethods
  end
end

以上代码的思路很容看清楚,树形结构肯定有parent,也有children,而TreeBase只是提供一个处理框架,具体的表还是得看include了这个module的类,所以在class_name中用的是self.class.name. 同理,在查找节点时,也用的self.class.where(p_id: nil)

问题

这个时候,问题发生了,找打一个node没问题,但是node.parent的时候,就会报错Object doesn't support#inspect.

最终的原因在于moduleincluded,InstanceMethods,ClassMethods的上下文不一样,InstanceMethods定义的是实例方法,所以默认的上下文就是实例,于是可以这样定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module TreeBase
  extend ActiveSupport::Concern
  module InstanceMethods
   #判断是否有子节点
    def has_children?
      children.count > 0
    end

    #计算全局顺序
    def compute_overall_idx
      if parent.nil?
        order_idx.to_s.rjust(2,'0')
      else
        "#{parent.overall_idx}_" + order_idx.to_s.rjust(2,'0')
      end
    end
  end
end

children这样的属性或者实例方法能直接调用.

而在included中,上下文是具体的类,所以self是形如GrammarTree这样的具体类,因此self.class就是Class了,而self.class.name就是'Class',而我们期待的实际是'GrammarTree'

就这样,出现了Object doesn't support#inspect这个问题,衍生出来的,如果执行node.has_children?,因为node.children已经跪了,再来chidlren.count > 0 就会报错undefined method 'scoped' for Class:Class

解决

self.class.name改成name,由于已经处于类的上下文,所以直接用name即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  included do
    attr_accessible :p_id, :node_name, :order_idx, :level, :overall_idx
    belongs_to :parent, class_name: name, foreign_key: "p_id"
    has_many :children, class_name: name, foreign_key: "p_id", dependent: :restrict, order: :order_idx
    validates :node_name, presence: true

    default_value_for :level do |node|
      node.parent.nil? ? 0 : (node.parent.level + 1)
    end
    default_value_for :order_idx do |node|
      if node.parent.nil?
        (where(p_id: nil).maximum(:order_idx) || 0) + 1
      else
        (node.parent.children.maximum(:order_idx) || 0) + 1
      end
    end
    default_value_for :overall_idx do |node|
      node.compute_overall_idx
    end

    after_save :reset_index
  end

其中,default_value_for是设置对象默认值的,其上下文应该是实例对象而不是类,所以需要在代码块中传入node.

Comments

PMP HeadFirst CH2

Ch 2. Organizations, constrains, and projects

 Organizations: Functional -> Weak Matrix -> Balanced Matrix -> Strong Matrix -> Projected



 Operational Work: Which has no beginning and has no end.



 Stackholders are impacted by your project.

 A stackholder is anyone who is affected either positively or negatively by the cost, time, scope, resources, quality, or risk of your project.

 It's possible to "turn around" a negative stackholder.



 Project constrains: Time , Cost, Scope, Resources, Quality, Risk

 All six of the constrains are related to each other.

 There is almost never an easy, obvious trade-off where you can sacrifice one to improve the others.



 A portfolio charter will give the business goal that a group of projects and programs will accomplish as part of a portfolio.

 A program is a group of projects that should be managed together because of interdependencies.
Comments

Ckeditor上传文件失败

Rails: 3.2.6

使用的是Ckeditor的Rails Gem.

突然不能上传文件,控制台显示在上传插入数据库时直接rollback了

于是重载app/controllers/ckeditor/application_controller.rb的respond_with_asset(asset)方法,

将asset.save,改为asset.save!

查看抛出的异常,是文件大小超出范围,显示必须在0-2048 Bytes之间,我还以为是文件没有拷贝过去,于是大小是0。

这时辉神出现了,他指出,2.megabytes不应该是2048啊。于是测试ActiveSupport,这个没问题,网上一搜,才发现,god这个gem重载了这个方法.于是2.megabytes变成了2048

但是最终没有把god注销,而是在代码中直接使用了220482048

Comments

微信背后的产品观

http://www.geekpark.net/read/view/161904

http://it.sohu.com/20120725/n349005014.shtml

1.懒惰导致发明,懒惰是创新的动力

2.时尚是重要动力,看别人都在用,不要太“工具化”

3.用户是乌合之众,群体智商低于个体智商

4.用户反馈能帮助完善体验,但不会告诉你要做什么新东西

5.做得越多可能错得越多

6.宁愿损失功能也不损失体验

7.产品,还是运营?

8.让用户推动用户

9.极简方能不被超越

10.在单点获得口碑,而不是一些列可有可无的特性

11.上线是为了验证想法,是改进的开始

12.如果没有自然增长 就不必推广

13.如果解决方案非常复杂,一定是问 题错了

14.理性的分析是功利而不完美的

15.你无法重新发明电话,但可以改变打电话的方式

16.没有设计,只有解决问题

17.“管理”是不自然的

18.单线索最美

19.让欢迎页成为你的产品发布会

20.一些避免使用的词语 • 不用“吧”(“立即注册吧”) • 不用“哦”(“网速很慢哦”) • 勉强用户的句式 (“还不邀请朋友”) • 不用“成功”(“已保存成功”,有已保存失败?) • 用“你”,不用“您”

21.一旦一个功能需要文字解释,这个功能的设计已经失败了

22.腾讯给大家各种“钻”(腾讯会员与特权体系,编者注),“钻”体现了什么心理?其实都体现了人性的这几个弱点。各种黄钻、绿钻,他会贪,他要升级; 他会嗔,他会跟人比较,说你的钻比我的等级高,所以我也要升上去;他会痴,觉得我一定要把所有的钻给收齐。不是说所有的东西都要去做“钻”之类的东西,即使是一个体验好的产品,就像苹果的手机,同样会对用户产生这样的吸引力,因为这是人性本身的共同弱点。 所以当我们在做一个产品的时候,我们在研究人性,而不是研究一个产品的逻辑。

23.当我们研究不到用户需求时,我们就会说只要让我们自己用得爽,这个是比较容易做到的一点。怎么样让用户用得爽呢?如果光凭一些体验的话,其实是有一个比较简单的方法,把自己当作一个傻瓜来用产品,傻瓜心态。

24.之前有一句话说 web 已死,大概从移动互联网的发展趋势来说,确实是有这个趋势。手机的增长非常快,手机应用的增长也非常快,可能很多人还是集中在 web 这块,但是这一刻,我觉得不管怎么样都要把眼光放到手机里去,因为 PC 的不增长和手机的快速增长,对比实在是太强烈了。不管我们是做什么样的 web 产品,都应该试图扩展到手机端去,而手机端的话,浏览器可能不是一个主要的入口,APP 才是。

25.而且 APP 的趋势,不是要做一个大而全的 APP,而是做成尽可能小的 APP。为什么不是大而全的呢?因为用户很懒,我要看天气我就点天气的 APP, 我要看股票就点股票的 APP。

26.最好的方法是什么呢?是把对底层的规则梳理的更加清晰,然后能够发挥作用,而不是不断打补丁的方式。

27.这个可能非常难解释,我就比较简单的说一下。这里可能有些开发人员会非常理解,其实跟代码非常像,但你把代码变成复杂的系统的时候,它是有自己的结 构的。产品也是,很简单的一个产品可能包含了上百个功能在里面,这些功能你可以像写代码一样,按一个线性的方式把它串起来,但是也可以做成一个很有架构在 里面的东西。这是考验一个人对产品的见解是什么样的。我们心中一定要有一个产品的架构在这里,而不是说我们这个产品就是一大堆功能的集合,只是一个无序的 集合,那样就很糟糕了。那样他就没有自己的骨骼和系统架构。

移动互联网产品设计的原则   1、绝不考虑Web形态,一切考虑都基于APP。   2、产品优先级:   (1)有趣高于功能,产品必须有趣,必须Cool,才可能形成传播和口碑。   (2)功能高于交互,明确的功能满足明确的需求,用户不会在意炫酷交互效果。   (3)交互高于UI。便捷、快速的交互设计为先,围绕具体功能实现UI,而非有优质UI方案为此专门设立一个功能。   3、聚焦:一个APP只做一件事情,一个大而全的APP意味着全面的平庸。   4、永远一维化:让用户在一个维度里解决具体的问题,Twitter的Timeline就是一个好的范例。而类似Facebook、Path那样的滑出式菜单则是一个灾难,因为这使得产品拥有两个维度,加大了用户理解的困难。   5、保持主干清晰,枝干适度。产品的主要功能架构是产品的骨骼,它应该尽量保持简单、明了,不可以轻易变更,让用户无所适从。次要功能丰富主干,不可以喧宾夺主,尽量隐藏起来,而不要放在一级页面。   6、不要让用户选择。同一个页面之内,有多个入口;同一个功能,有多个实现方式;同一个界面,有多个展示方式。这对于用户来说是一种痛苦而非享受,因为他们只会因此而感觉到困惑和恐惧。用户宁可采取重复操作漫长而固定的操作路径,也不愿意使用多变的快捷方式。   7、隐藏技术,永远展现简单的、人性化的、符合人类直觉的界面。开发不可以为了炫技而展示功能,产品不可以为了炫耀而功能堆砌。   8、 拒绝个性化。除了依靠设计特色而立身的APP,换肤一类的个性化设计,除了让产品经理幻觉自己做了许多工作而自我满足之外,没有任何价值。它只能证明产品 经理对自己的产品不自信,因为自信的产品经理凭借默认皮肤就可以满足用户。延伸开去,一个好的产品,其功能应该满足全球用户需求,无需为地区做特别定制 化。   9、 产品一定程度上是为了满足人性中的贪嗔痴,这是用户的痛点。能把握住之后,产品经理应该超越其上,用产品帮助人们得以解脱。   10、想清楚自己究竟要做什么,不去迎合上司,不去讨好用户,不去取悦自己。   11、 分类!分类!分类!这是产品经理在确定产品主要功能构架之后,唯一应该为用户做的事情。分类无助于降低产品使用的难度,但是可以帮助用户认知产品和周边的世界。   12、永远围绕功能而做设计,永远不要倒过来做这件事情。   13、一个产品的基本功能不受用户认可,做加法也无济于事。   14、想不清楚一个功能点之前,宁可不做。   15、千万不要让用户在产品里“管理”什么。

Comments

Ckeditor的逆袭

原本用kindeditor毫无压力,也算支持国产,但是无奈,为了整合数学公式编辑器,只能改用ckeditor或者tinyMCE这两个主流大哥。

而tinyMCE又与Rails不能很好集成,只有原生的插件。一没有gem,二不能上传文件。

于是改用比较成熟的ckeditor,整合rails相当方便,上传等也一应俱全,还提供ActiveRecord, Mongid等持久化支持,和paperclip,carrierwave上传插件的支持。

gem "ckeditor", "3.7.1"
rails generate ckeditor:install --orm=active_record --backend=paperclip

一直使用很顺畅,直到碰到两个很恶心的问题:

  • ckeditor总会把内容自己套一层<p>标签

    这是因为ckeditor对于换行有三种模式,默认是<p>,改成br模式或者div模式即可解决问题,在config.js中加入:

config.enterMode = CKEDITOR.ENTER_BR;
config.shiftEnterMode = CKEDITOR.ENTER_BR;
  • HTML里面本来<table>标签在标签里面,在kindeditor里面,能正常显示在富文本编辑器里,但是ckeditor会自己把外面的标签移除,然后内嵌到table里的文字周围。

    原本以为是ckeditor自己怪异的行为,然后几乎花了一天时间去看ckeditor的源码以及详细设置,使用了很多方案:

config.removePlugins = 'scayt';
config.autoParagraph = false;
config.ignoreEmptyParagraph = false;

都不行,后来在一个帖子里看到,span标签属于inline element,而table属于block element,从规范和合理的角度出发,block是不能内嵌到inline element的。 所以ckeditor进行了检查并处理。确实在ckeditor的dtd中也对各类标签进行了定义

ckeditor总的来说还是很不错,但是体积比Kindeditor稍大,如果不是特别的需求,我会选择kindeditor.

下一篇着重讲下数学公式编辑器的集成,从官方的php移植到了rails上。

Comments

以史为镜

我记得”以史为镜”,因为一篇文章。

那是12年前,读初二的时候,当时有幸进入鲁迅文学院的少年作家班学习,在某一期的内部通讯上,看到一篇古怪题目的文章,叫《猫照镜》,详细的内容已经记不清了,但是记得他的写作手法有卡夫卡变形记的影子,用一个猫照镜这样的荒诞的而无意义的情景影射到了魏征身上,魏征劝谏唐太宗:以铜为镜可以正衣冠,以人为镜可以明得失,以史为镜可以知兴替。

家里不乏二月河写的历史小说,也有各类正史,野史,但是始终沉不下心。看到厚厚的一沓,总是有些心虚,尤其以前翻看资治通鉴时,看到一大堆的编年纪事,也觉得索然无味。

现在,努力地去在睡前用kindle去看《资治通鉴》,数月有余,只看了6%。看到汉武帝了。

总结起来,《资治通鉴》现在给我的感想就挺多了:

  1. 博大精深。其中很多桥段,例如《触龙说赵太后》,《鸿门宴》,《谏逐客书》等,在看时,几乎都能背出来,但是现在去看才慢慢 体会到里面的智慧和精髓,回想以前摇头晃脑的背诵,多少感觉有些无意义,还不如把这功夫细心地去品读。不过这也是语文教育的通病,回想小学为了形式化的读书笔记,把各种不认识的词语作为优美词,把长句子抄下来,放到优美句里,就觉得好笑。这里,让我想起了高中的语文老师,张瑛,她讲课异常丰富多彩,入门三分,依然记得她讲触龙说赵太后时,还画出了碉堡和作战示意图,让我是真的领悟到了,迂回,侧面进攻的重要性。

  2. 有些与中学学的历史相悖。例如焚书坑儒,记得初二学历史的时候,是把焚书坑儒和秦皇统一度量衡的大一统策略一起阐述的,映像中,是为了统一文化。但是在《资治通鉴》里,焚书不过是为了防止民众开化,而实行的愚民政策,而坑儒,也根本没有历史课上讲的惨烈,是有秦始皇原本尊敬尊敬的儒生,反过来嘲笑秦始皇,于是秦始皇就坑杀了200多个。这些东西也都无法去考证。

  3. 为臣很艰辛。有人说看《资治通鉴》可以学到帝王之术,而我现在的感觉是,学到更多的是为臣的技巧。通篇大量地阐述各种人才,雄才,鬼才,如何劝谏,如何献策,如何说服帝王,协助帝王,成就自己。苏秦,张仪,一张嘴就能合纵连横,配六国相印。惊叹他们缜密的思维,和雄辩的口才。但也感慨,基本上大臣下场都很惨。要不功高盖主死得很惨,例如韩信,要不就是自己后来犯浑,李斯当初协助秦始皇 统一六国,无比厉害,但是后来,就战战栗栗,只为保住自己的丞相之位,唯唯诺诺,最终也被腰斩。 时势造英雄,审时度势也是英雄的必备条件。不以无过为贤,而已改过为美。

  4. 后宫确实不安宁,各种太后的势力祸乱人间。

看完汉武帝,就看《史记》,史记恰好讲到汉武帝元狩元年。

编年体到纪传体。都体会一下。

Comments

厦门

以“厦门”为题,一下笔,就不由自主地想说“厦门是我一直都想去的地方”。但是,却不是。

厦门,一直被广为传颂着,厦门的空气,鼓浪屿上的精致小店,各种适合步行的观光路线,美丽的海滩,漂亮的海岸线。但是这种铺天盖地的宣传和赞叹,让我不由得反感,哪怕真的如梦似幻。

以上烂俗的映像,是我对厦门下意识的感觉。

其次的感觉是,秦瑞林在厦大。

他是本科时候成绩最好的家伙,报送到了厦大计算机系,如果他成绩不好,那就天理不容了。原因有二:

其一,他学习态度实在是太好了,感觉时时刻刻都活在高考拼搏的岁月。开学第一天,他就能高高兴兴地左手拎着象征性的塑料袋,里面装着崭新的新课本,右手拎着代表性的硕大无比的水壶,去自习。由于习性的差异,基本和他难以照面,除了上课时间。

其二,他有一般成绩特别好的同学的一个共性,或多或少存在些癖好。例如塑料袋,例如水壶,例如无论早晚的一声“早上好”。一天之计在于晨,在他身上得到淋漓的体现。他就像早上八九点钟的太阳,时时刻刻都像朝阳般地绽放着自己的智慧,一次有一次地逼近满分。也毫无顾忌地在班级茶话会时,鄙视着大家,“如果我不是高三的 时候看了200部电影,我就不会比高二参加高考考得还差,来到南师。”除了掌声,我不知道如何表达我的心情了。

Comments

骑行

今天骑了16KM+,当时不觉得累,现在大腿都是滚烫的。

Comments