写给而立之年的自己

  • 多做,少说。
  • 冲动是魔鬼,但魔鬼起码比唯唯诺诺的小鬼好。
  • 技术是安家之本,并不代表是职业的全部。
  • 效率有时候比什么都重要。
  • 二师兄队友真的很坑。
  • E 文呢?学还是不学,有个不错的老师还在等。
  • 做好 “ 蜻蜓助手” 搞定一家单位,年底没做到!见人发钱!
  • 天时地利人和是条件,但是不代表可以一直等。机会来了,自己没有干货是行不通的。

好了,就这么多吧。

CentOS6 部署 Rails 工程的一些破事儿

花了整整一天半来搞定环境部署。如果要部署RoR环境我强烈建议新手使用Ubuntu来部署。确实能够省掉很多问题。

详情可以参考这个链接:

http://www.yangzhiping.com/tech/ubuntu-ree-nginx-passenger-rails3.blog.html

在部署的过程中一直都很顺利,但是有几个点需要特别说明。

  1. 如果环境是使用 RVM 搭建的,那么请不要使用 ROOT 登录搭建,原因在于使用 ROOT 安装时RUBY 的环境会存在于 ROOT 根目录中而使用 passenger 的时候会由于权限不足,无法访问 ROOT 目录中的环境导致环境部署失败。
  2. 如果 gem 中存在 github 的地址,例如:
    gem 'mini_magick', :git => 'git://github.com/minimagick/minimagick.git'
    在安装 gem 的时候需要 Try running bundle install --deployment
  3. mysql2 的使用在 windows7 中是存在问题的。但是mysql2的性能要大大由于第一版的驱动程序。安装步骤如下:
    • 下载驱动程序:http://cdn.mysql.com/Downloads/Connector-C/mysql-connector-c-noinstall-6.0.2-win32.zip
    • 拷贝相关文件到RUBY目录,例子:“lib\libmysql.dll C:\RailsInstaller\Ruby1.9.3\bin”
    • 运行安装命令:gem install mysql2 — ‘–with-mysql-lib=”D:/mysql-connector/lib” –with-mysql-include=”D:/mysql-connector/include”

通过群里的朋友介绍,Rails 中的 gem 在 Amazon 服务的相关 gem 包也会存在一些问题。具体没详细请教,不过既然选择了 Rails 作为开发框架,建议切换到 Linux 环境应该会比较舒服。

CentOS 配置 ROR 环境

2014.3.20 日更新,我建议大家不要使用我文章中写的内容。因为各个版本的服务器有可能安装上有一些区别。自己本人安装了几个环境。各种坑爹,为此我还特意请教了刘辉哥。大哥很慷慨的发送了一个详细教程。本人也共享给大家。强烈建议参考连接中的安装步骤,省掉不必要的麻烦。

如何快速正确的安装 Ruby, Rails 运行环境在 Ubuntu 12.04 Server 上安装部署 Ruby on Rails 应用

经过一个上午的折腾,终于把ROR环境在CentOS中搞定,绕了很多弯路,把文章写下来总结一下。

安装步骤:

  1. 更新Python
    centos 中默认安装的python是2.4的版本,因为新版的rails需要提供nodejs的相关支持,需要更新python,更新文章可以直接移步到这个链接 http://www.tomtalk.net/wiki/Python
  2. 安装相关的依赖包
    #yum install gcc gcc-c++ openssl* readline* ncurses* zlib* libxml* libjpeg* libpng* libxslt* libtool*
  3. 安装 NodeJS
    wget http://nodejs.org/dist/v0.8.5/node-v0.8.5.tar.gz
    tar zvxf node-v0.8.5.tar.gz
    cd node-v0.8.5
    ./configure
    make && make install
  4. 建议先安装 YAML 否则可能会引起 gem 安装的一个异常,具体可见:http://collectiveidea.com/blog/archives/2011/10/31/install-ruby-193-with-libyaml-on-centos/

     wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
     tar xzvf yaml-0.1.4.tar.gz
     cd yaml-0.1.4
     ./configure --prefix=/usr/local
     make
     make install
  5. 安装 Ruby 1.9.3
    wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p0.tar.gz
    tar xzvf ruby-1.9.3-p0.tar.gz
    cd ruby-1.9.3-p0
    ./configure --prefix=/usr/local --enable-shared --disable-install-doc --with-opt-dir=/usr/local/lib
    make
    make install
  6. 升级 gem 并安装 Rails
    如果gem安装失败,可以通过下载源代码的方式进行安装。

    wget http://rubyforge.org/frs/download.php/74445/rubygems-1.6.2.tgz
    tar zxvf rubygems-1.6.2.tgz
    cd rubygems-1.6.2
    ruby setup.rb

    gem 安装成功则直接执行下一步

    gem update --system
    gem install rdoc
    gem install rails
    rails -v

博客开始更新……

2013年的最后两个月,一直忙于外包项目,“可乐加糖”的博客一直处于停更状态。非常遗憾,在这个项目中的预想和现实的差距实在是太大。通过这一次失败的初创经历,也值得让自己反省在这一系列的计划中,到底做错了一些什么东西,定价、市场、客户需求、以及产品最终带来的收益和效果。种种迹象都能给一个产品的定位有一个清晰的指标。这也是大部分的初创容易犯下的错误。

常常都说一个产品的价值体现在能够给用户带来多少利润,其实这也就是一个产品为什么能够得以生存的初衷,“时刻知道客户最需要什么”这句看似简单的话实际上蕴含的商业价值却是通过一个个成型的产品体现出来的。而这个外包的项目我想就是单纯的犯了这个简单的错误而导致接下来的项目岌岌可危。

作为一个开发人员,一个有想法创业的程序猿,我想分享几点各位:

  1. 做任何一款产品也好,考虑它的卖点。

    第一款产品,也就是一个简单的企业网站,我印象中2008年就有成堆的企业建站软件了,就这个老掉牙的项目而言,真真的客户定制化需求是非常多的。单单一个网站能够给普通的企业客户带来多大的利润?如果能够和淘宝或者任意电商结合。这种简单的2000块一个的建站系统我想应该完全应该被淘汰了。通过网络创造价值,而不是简单的一个网络名片。通过更好的电商服务给企业创造价值,应该更好的能够被更多的企业客户接受。

  2. 求精不求全

    坦白来说,一直在大公司工作,这样的东西见得多了,所谓“企业巨头“动不动就是要打造平台。但是就公司失败的产品来看,一开始瞄准平台的产品失败率远远大于功能单一的产品。功能单一其实也就是简单的意味着能够更好、更快的被用户接受。通过迅速的积累用户慢慢产生成熟的平台。

  3. 注意收集用户的数据

    不管是豌豆荚、淘宝、亚马逊、新浪微博、QQ空间 都是在无时不刻的手机用户的数据。现在火爆的微信开发也是一样,在这个方面,我想阿里系的产品应该也是收集用户的鼻祖。试想,如果有软件能够收集到何时何地、什么时间段、什么地域的消费数据、人群数据、购买商品种类数据、消费类型数据能够及时提供给需要的企业客户,数据的价值也就不用多说了。

  4. 技术不是重点,快速迭代才能跟上节奏。

    前期考虑太多的技术、事实证明是完全没必要。快速迭代占领市场。这个也不用多话痨了。事实证明就是如此。

关于Sencha ExtJS 中 Datefield 控件 load 无法加载数据的问题

Sencha ExtJS 开发中一个比较多的功能就是在编辑某条数据列的时候如果有 datefield 控件时间无法加载入正确的栏目中。

1

而 textfield 控件则能够通过服务器端返回的数据正确加载到相应的控件中,通过官网的论坛给出的答案是:需要修改服务器端返回的时间格式


{
desc: "成功",
totalResult: 9,
items: [
	{
		userId: "null1383919764373",
		userAccount: "yz",
		userIcon: "",
		userMobile: "13888889991",
		userNick: "园长",
		userType: "3",
		regTime: "2013-11-08 22:09:24",
		updateTime: "2013-11-08 22:09:24",
		status: "0",
		point: 0,
		realName: "园长",
		email: "balkc@11.com",
		sex: "0",
		birthday: "2013-11-06 00:00:00",
		orgs: [{
			updateTime: "2013-11-08 22:09:24",
			status: "0"
		}]
	}
	...
Ext.getCmp('base_form').getForm().on({
        actioncomplete: function(form, action) {
            if (action.type === 'load') {
                if (action.result.success) {
                    //绑定开始时间
                    var date = new Date(action.result.data.regTime);
                    var edate = new Date(action.result.data.updateTime);
                    form.setValues({
                        regTime: Ext.Date.format(date,"Y-m-d"),
                        updateTime: Ext.Date.format(edate,"Y-m-d")
                    });
                }
            }
        }
    });

通过使用 Ext.Date.format(框架内置)方法格式化返回的时间格式就能够正常的把时间设置进入控件中。

Javascript属性constructor/prototype的底层原理(转)

最近一直在阅读 JQuery 的源码,涉及到核心组件,需要复习一下 JavaScript 的底层属性,把这篇文章转载过来,作为资料。
原帖地址:http://blog.csdn.net/hikvision_java_gyh/article/details/8937157

在Javascript语言中,constructor属性是专门为function而设计的,它存在于每一个function的prototype属性中。这个constructor保存了指向function的一个引用。在定义一个函数(代码如下所示)时,


function F() {   
    // some code  
 }

JavaScript内部会执行如下几个动作:

为该函数添加一个原形属性(即prototype对象).

为prototype对象额外添加一个constructor属性,并且该属性保存指向函数F的一个引用。

这样当我们把函数F作为自定义构造函数来创建对象的时候,对象实例内部会自动保存一个指向其构造函数(这里就是我们的自定义构造函数F)的prototype对象的一个属性__proto__,所以我们在每一个对象实例中就可以访问构造函数的prototype所有拥有的全部属性和方法,就好像它们是实例自己的一样。

当然该实例也有一个constructor属性了(从prototype那里获得的),这时候constructor的作用就很明显了,因为在这时,每一个对象实例都可以通过constrcutor对象访问它的构造函数,请看下面代码:

 

[javascript] view plaincopy


var f = new F();
alert(f.constructor === F);// output true
alert(f.constructor === F.prototype.constructor);// output true

我们可以利用这个特性来完成下面的事情: 对象类型判断,如

[javascript] view plaincopy


if(f.constructor === F) {
    // do sth with F
}

其实constructor的出现原本就是用来进行对象类型判断的,但是constructor属性易变,不可信赖。
我们有一种更加安全可靠的判定方法:instanceof 操作符。
下面代码仍然返回true


if(f instanceof F) {
    // do sth with F
}.

原型链继承,由于constructor存在于prototype对象上,因此我们可以结合constructor沿着原型链找到最原始的构造函数,如下面代码:


function Base() {
}
// Sub1 inherited from Base through prototype chain
function Sub1() {
}
Sub1.prototype = new Base();
Sub1.prototype.constructor = Sub1;
Sub1.superclass = Base.prototype;
// Sub2 inherited from Sub1 through prototype chain
function Sub2() {
}
Sub2.prototype = new Sub1();
Sub2.prototype.constructor = Sub2;
Sub2.superclass = Sub1.prototype;
// Test prototype chain
alert(Sub2.prototype.constructor);
// function Sub2(){}
alert(Sub2.superclass.constructor);
// function Sub1(){}
alert(Sub2.superclass.constructor.superclass.constructor);
// function Base(){}

上面的例子只是为了说明constructor在原型链中的作用,更实际一点的意义在于:一个子类对象可以获得其父类的所有属性和方法,称之为继承,关于继承我们有好多可以分析和讨论,本篇限于篇幅不在此讨论。
一个容易掉入的陷阱(gotchas) 之前提到constructor易变,那是因为函数的prototype属性容易被更改,我们用时下很流行的编码方式来说明问题,请看下面的示例代码:


function F() {

}
F.prototype = {
    _name:Eric,
    getName: function () {
        return this._name;
    }
}

初看这种方式并无问题,但是你会发现下面的代码失效了:

var f = new F();
alert(f.constructor === F); // output false

怎么回事?F不是实例对象f的构造函数了吗?
当然是!只不过构造函数F的原型被开发者重写了,这种方式将原有的prototype对象用一个对象的字面量{}来代替。
而新建的对象{}只是Object的一个实例,系统(或者说浏览器)在解析的时候并不会在{}上自动添加一个constructor属性,因为这是function创建时的专属操作,仅当你声明函数的时候解析器才会做此动作。
然而你会发现constructor并不是不存在的,下面代码可以测试它的存在性:

alert(typeof f.constructor == ‘undefined’);// output false

既然存在,那这个constructor是从哪儿冒出来的呢?

我们要回头分析这个对象字面量{}。

因为{}是创建对象的一种简写,所以{}相当于是new Object()。

那既然{}是Object的实例,自然而然他获得一个指向构造函数Object()的prototype属性的一个引用__proto__,又因为Object.prototype上有一个指向Object本身的constructor属性。所以可以看出这个constructor其实就是Object.prototype的constructor,下面代码可以验证其结论:

alert(f.constructor === Object.prototype.constructor);//output true
alert(f.constructor === Object);// also output true

一个解决办法就是手动恢复他的constructor,下面代码非常好地解决了这个问题:


function F() {
}
F.prototype = {
    constructor: F, /* reset constructor */
    _name: Eric,
    getName: function () {
        return this._name;
    }
};

之后一切恢复正常,constructor重新获得的构造函数的引用,我们可以再一次测试上面的代码,这次返回true
var f = new F();
alert(f.constructor === F); // output true this time ^^
解惑:构造函数上怎么还有一个constructor?它又是哪儿来的?
细心的朋友会发现,像JavaScript内建的构造函数,如Array, RegExp, String, Number, Object, Function等等居然自己也有一个constructor:
alert(typeof Array.constructor != ‘undefined’);// output true
经过测试发现,此物非彼物它和prototype上constructor不是同一个对象,他们是共存的:
alert(typeof Array.constructor != ‘undefined’);// output true
alert(typeof Array.prototype.constructor === Array); // output true
不过这件事情也是好理解的,因为构造函数也是函数。
是函数说明它就是Function构造函数的实例对象,自然他内部也有一个指向Function.prototype的内部引用__proto__啦。
因此我们很容易得出结论,这个constructor(构造函数上的constructor不是prototype上的)其实就是Function构造函数的引用:
alert(Array.constructor === Function);// output true
alert(Function.constructor === Function); // output true
OK, constructor从此真相大白,你不在对它陌生了~

Sencha Extjs4.2 皮肤制作

话不多说,直接上图:

1

搜了一把皮肤制作,大多数都是英文文档,看了几遍差不多熟练了之后就把皮肤问题得以搞定,记录下来方便下次使用。

步骤:

1. 安装环境,JDK、ruby、compass、sass (JDK 通过下载安装,RUBY 通过下载安装- http://rubyinstaller.og ,sass 通过Ruby 中的 gem 能够自动安装)

2. 下载 SenchaCmd-3.1.2.342-windows.exe 、SenchaSDKTools-2.0.0-beta3-windows.exe (Linux 环境请自行下载安装包,配置PATH)

3. 环境搭建完毕之后,开始构建工程,使用命令
sencha –sdk /extjs的路径/ generate app 工程名 工程存放的路径
2

3

继续阅读

Sencha ExtJS 常见问题集合贴

最近一直在使用Sencha进行前端开发,单独开一个帖子,用于常见问题的整理。会陆陆续续往里面添加一些内容,同事也希望能够帮助到大家。

ExtJS submit 提交导致 emptyText 提交进入表单:

win.form.submit({
     submitEmptyText: false,
     url : 'xxxxx',
     method : 'post'
});

ExtJS 限制text最大字符数。

{
	fieldLabel: '教育证号',
	name:"teacher.educationCardNo",
	emptyText:'请输入教育证号',
	enforceMaxLength:true,   //关键是这个
	maxLength:18,
	value:""
}

ExtJS Ajax 提交SESSION失效的问题。

1. 首先通过后端返回 session timeout 的 header 信息,再通过 response.getResponseHeader 来判断是否存在这样的信息来确定session是否失效,代码如下:

Ext.onReady(function(){
	//请求超时的处理开始
	Ext.Ajax.on('requestcomplete', checkUserSessionStatus, this);
	function checkUserSessionStatus(conn, response, options) {
	    var sessionStatus = response.getResponseHeader("sessionstatus");
	    if (typeof(sessionStatus) != "undefined") {
	        Ext.Msg.alert('提示', '会话超时,请重新登录!',
	        function(btn, text) {
	            if (btn == 'ok') {
	                var redirect = root_path;
	                window.location = redirect;
	            }
	        });
	    }
	};
......

Ajax 的提交失败问题。

Ext.Ajax.request 提交与 Ext.Form.panel 中的 submit 都是属于 Ajax 提交,但是前者判断返回不是由服务器端的 { success :false …} 来决定,而是通过返回的 responseText 中的返回值来判断, from 中的提交,可通过 failure 函数来判定。代码如下:

Ajax 返回失败:

Ext.Ajax.request({
    url: url,
    timeout: 6000,
    success: function(response) {
        var result = Ext.decode(response.responseText);
        if (result.success) {
            Ext.Msg.alert("提示", "数据删除成功");
        } else {
            Ext.Msg.alert("提示", result.message);
        }
        parentStore.reload();
    },
    error: function(response) {
        Ext.Msg.alert("提示", "对不起,操作失败。");
        parentStore.reload();
    }
});

form 表单提交失败:

Ext.getCmp("wx_student_add").submit({
    submitEmptyText: false,
    clientValidation: true,
    url: this.url,
    method: 'post',
    success: function(form, action) {
        top.Ext.Msg.alert("提示", "保存成功");
        Ext.getCmp("tw_addstudent").destroy();
        student_store.reload();
    },
    failure: function(form, action) {
        Ext.Msg.alert("提示", "数据提交失败");
        throw new Error("用户数据保存失败,请检查服务器端返回");
    }
});

待续……

Html5 属性浏览器速查

网址:http://caniuse.com/#index

Html5属性支持

Html5属性支持

该网站提供了非常丰富的H5以及各种新型浏览器API,并且能够在网站上快速搜索某一属性在各个浏览器以及设备上的支持情况。
例如:搜索GEOLOCATION属性的支持。

Html5属性支持

Html5属性支持

这样极大的方便了日常H5开发的浏览器支持一览,如果需要支持低端浏览器,可以在重构HTML之前就查询相应的支持,从而判断如何使用降级版本处理方案。

ExtJs 自定义组件事件绑定

优化了一下代码,结果如下。

调用:

<script type="text/javascript">
function aaa(){
	var student_panel = new WX.student.AddStudent({
		callback_fun:function(){
			alert("我是页面的方法");
		}
	}).show();
}
</script>

组件定义

Ext.define('WX.student.AddStudent', {
	
    extend: 'Ext.window.Window',

    modal:true,
    height: 585,
    width: 590,
    layout: {
        type: 'fit'
    },
    title: '新增学生',
    //用于组件函数回调
    callback_fun:function(){},
    initComponent: function() {
    	
        var me = this;
        
        Ext.applyIf(me, {
            items: [
                {
                    waitTitle: '加载中...',
                    items: [
                        ......
                    ],
                    buttons:[{
                    	text:'保存',
                    	scope:this,                  // <============== 关键参数 
                    	handler:function(){
                    		//DO SOMETHING...
                    		alert("组件的事件");
                    		this.callback_fun();
                    	}
                    }]
                }
            ]
        });
        me.callParent(arguments);
    }

});