2012/09/04

CentOS で Rails など

いよいよ Ruby on Rails


やっとここまで来た。
まずは rvm で ruby と rails を入れる。
$ curl -L https://get.rvm.io | bash -s stable --ruby

このまま gem してもいいのかなぁと思いながらも
$ curl -L https://get.rvm.io | bash -s stable --rails

などとしてしまった。

$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]

$ rails -v
Rails 3.2.8

ちょっと、作ってみる。
$ rails new foo --database=postgresql

最後のほうでエラー、pg を入れろといってくるので
$ gem install pg -v '0.14.1'

とするも、やっぱりエラー。--with-pg-config で指定しろといってくる。そこで、
$ gem install pg -v '0.14.1' --with-pg-config=/usr/pgsql-9.1/bin/pg_config

としてもエラー!! えーっと思いながらググったら
$ gem install pg -v '0.14.1' -- --with-pg-config=/usr/pgsql-9.1/bin/pg_config

ハイフンが要るんだそうで。

このあと、vi Gemfile で therubyracer を有効にして
$ bundle install

$ rails server
ブラウザから http://localhost:3000 で無事アクセスできた。

CentOS データベースなど

PostgreSQL9.1 をインストールしてみる

yum標準でインストールされるのが 8.4.12 だったので 9 シリーズを入れてみる。

ここにいって wget する。
http://yum.pgrpms.org/reporpms/
目的の CentOS6 用 9.1

# wget http://yum.pgrpms.org/9.1/redhat/rhel-6-i386/pgdg-centos91-9.1-4.noarch.rpm

とってきたら rpm する。
# rpm -ivh pgdg-centos91-9.1-4.noarch.rpm

設定ファイルの修正
# vi /etc/yum.repos.d/CentOS-Base.repo

 [updates] のセクションに追記
exclude=postgres*

yum でインストール
# yum install postgresql91-server

postgresユーザにスイッチして、PostgreSQL の初期化
$  /usr/pgsql-9.1/bin/initdb

サーバの起動
$ /usr/pgsql-9.1/bin/pg_ctl -D /var/lib/pgsql/9.1/data -l logfile start


今のところ、覚え書きレベルのエントリーでした。

<追記>

付属する機能も入れたほうが後々引っかからない。

# yum install postgresql91-devel
# yum install postgresql91-contrib

適当なデータベースを作って psql で入る。
=> select version();
--------------------------------------------------------------
PostgreSQL 9.1.5 on i686-pc-linux-gnu, ........

でも psql は 8.4.12 で「psql の機能の中で、動作しないものがあるかもしれません。」なんて言われてしまっている…

CentOS ネットワークなど

CentOS 6.3 をインストールして起動するけど、その度にネットワークが接続されてない。


で、設定を見てみると。

メニューから、システム/設定/ネットワーク接続

 リストから System eth0 を選択して「編集...」

「自動接続する」のチェックボックスを「ON」にする

再起動して確認。

これをコマンドラインでどうやって設定するかは・・・まだ調べてません。

2012/08/30

DataGridView など

はじめに

C# と PostgreSQL であれこれとやっています。DataGridView が便利そうなのですが、なかなか使いこなせません。で、いままでは ListView なんかを使って誤魔化していたのですが、やっぱりちゃんと DataGridView 使いたいよねということで、気合を入れて頑張ってみました。

住所録アプリです。


メイン画面はこんな感じ。DataGridView がどーんと表示されています。

「行を追加」ボタンで、カーソルがある行の下に空白行が表示されます。
「行を削除」で、カーソルがある行が削除されます。
「保存」で、画面上のデータがデータベースに反映されます。

PostgreSQL との接続には Npgsql を使用しています。ADO 経由の接続もあるのですが、ドライバを別途インストールしないといけないので Npgsql にしました。

 プログラムの起動

起動時にデータベースに接続にいって、該当テーブルを DataGridView に紐付けします。

接続はこんな感じ。
接続に必要な情報は app.config に入れています。


        public static NpgsqlConnection conn;
        public static bool connect_db()
        {
            Properties.Settings.Default.Reload();
            string connection_string = "Server=" + Properties.Settings.Default.Server + ";"
                + "Port=" + Properties.Settings.Default.Port + ";"
                + "User Id=" + Properties.Settings.Default.User_Id + ";"
                + "Password=" + Properties.Settings.Default.Password + ";"
                + "Database=" + Properties.Settings.Default.Database + ";";
            conn = new NpgsqlConnection(connection_string);
            try
            {
                conn.Open();
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("DataBase Open Error:" + ex.Message);
                return false;
            }
        }

Form の OnLoad のタイミングでデータを取ってきます。

            Database.GetData();
            dataGridView1.DataSource = Database.dataSet;
            dataGridView1.DataMember = "address";

Database.GetData() は、こんな感じ。
ちょっと、ゴチャゴチャしてますね。

        public static void GetData()
        {
            dataSet = new System.Data.DataSet();
            dataAdapter = new NpgsqlDataAdapter();
            string sql = "select * from address";

            dataAdapter.SelectCommand = new NpgsqlCommand(sql, Database.conn);

            sql = "insert into address (name, birthday, zipcode, addr, tel) values (:name, :birthday, :zipcode, :addr, :tel)";
            dataAdapter.InsertCommand = new NpgsqlCommand(sql, Database.conn);
            dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("name", NpgsqlTypes.NpgsqlDbType.Text, 0, "name", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("birthday", NpgsqlTypes.NpgsqlDbType.Timestamp, 0, "birthday", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("zipcode", NpgsqlTypes.NpgsqlDbType.Text, 0, "zipcode", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("addr", NpgsqlTypes.NpgsqlDbType.Text, 0, "addr", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("tel", NpgsqlTypes.NpgsqlDbType.Text, 0, "tel", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));

            sql = "update address set name = :name, birthday = :birthday, zipcode = :zipcode, addr = :addr, tel = :tel where id = :id";
            dataAdapter.UpdateCommand = new NpgsqlCommand(sql, Database.conn);
            dataAdapter.UpdateCommand.Parameters.Add(new NpgsqlParameter("name", NpgsqlTypes.NpgsqlDbType.Text, 0, "name", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.UpdateCommand.Parameters.Add(new NpgsqlParameter("birthday", NpgsqlTypes.NpgsqlDbType.Timestamp, 0, "birthday", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.UpdateCommand.Parameters.Add(new NpgsqlParameter("zipcode", NpgsqlTypes.NpgsqlDbType.Text, 0, "zipcode", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.UpdateCommand.Parameters.Add(new NpgsqlParameter("addr", NpgsqlTypes.NpgsqlDbType.Text, 0, "addr", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.UpdateCommand.Parameters.Add(new NpgsqlParameter("tel", NpgsqlTypes.NpgsqlDbType.Text, 0, "tel", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Current, DBNull.Value));
            dataAdapter.UpdateCommand.Parameters.Add(new NpgsqlParameter("id", NpgsqlTypes.NpgsqlDbType.Integer, 0, "id", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Original, DBNull.Value));

            sql = "delete from address where id = :id";
            dataAdapter.DeleteCommand = new NpgsqlCommand(sql, Database.conn);
            dataAdapter.DeleteCommand.Parameters.Add(new NpgsqlParameter("id", NpgsqlTypes.NpgsqlDbType.Integer, 0, "id", System.Data.ParameterDirection.Input, false, 0, 0, System.Data.DataRowVersion.Original, DBNull.Value));

            dataAdapter.Fill(dataSet, "address");
        }

これで表示はできますが、項目見出しが英語のままです。データベースには comment で日本語の情報を登録していますのでこれを使って項目見出しを日本語にします。

            Utils.SetHeaderString(dataGridView1, Database.GetComment("address"));

Database.GetComment() が、コメントを取ってくる部分。
Utils.SetHeaderString() が、コメントを DataGridView の HeaderText に当てはめる部分です。

        public static Hashtable GetComment(string table_name)
        {
            Hashtable ht = new Hashtable();
            NpgsqlCommand command = new NpgsqlCommand("select "
                + "  attr.attname as column_name, "
                + "  des2.description as column_comment "
                + "from "
                + "  pg_catalog.pg_class a "
                + "    inner join pg_catalog.pg_namespace ns on a.relnamespace = ns.oid "
                + "    inner join pg_catalog.pg_attribute attr on a.oid = attr.attrelid and attr.attnum > 0 "
                + "    left join pg_catalog.pg_description des2 on a.oid = des2.objoid and attr.attnum = des2.objsubid "
                + "where "
                + "  a.relkind IN ('r', 'v') "
                + "  and a.relname = :table_name "
                + "  and ns.nspname IN ('public') "
                , conn);
            command.Parameters.Add(new NpgsqlParameter("table_name", NpgsqlTypes.NpgsqlDbType.Text));
            command.Parameters["table_name"].Value = table_name;

            NpgsqlDataReader dr = command.ExecuteReader();
            while (dr.Read())
            {
                ht.Add(dr["column_name"], dr["column_comment"]);
            }

            return ht;
        }


        public static void SetHeaderString(System.Windows.Forms.DataGridView grid, System.Collections.Hashtable hash)
        {
            for (int ii = 0; ii < grid.Columns.Count; ii++)
            {
                if (grid.Columns[ii].HeaderText == "id")
                {
                    grid.Columns[ii].Visible = false;
                }
                if (hash[grid.Columns[ii].HeaderText] != null)
                {
                    grid.Columns[ii].HeaderText = hash[grid.Columns[ii].HeaderText].ToString();
                }
            }
        }


行を追加

このボタンをクリックすると、カーソルがある行の下に空白行を挿入します。最終行が選択されている場合、データがない場合は、行が追加されます。

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            int insert_pos = 0;

            if (dataGridView1.Rows.Count > 0)
            {
                if (dataGridView1.CurrentRow == null)
                {
                    MessageBox.Show("一覧から選択して下さい");
                    return;
                }
                insert_pos = dataGridView1.CurrentRow.Index + 1;
            }

            //  挿入する行の生成
            DataRow newRow = Database.dataSet.Tables[0].NewRow();

            //  選択行の下に追加
            Database.dataSet.Tables[0].Rows.InsertAt(newRow, insert_pos);
        }

行を削除

このボタンをクリックすると、カーソルがある行が削除されます。DataGridView からです。まだデータベースからは削除されません。

        private void buttonDel_Click(object sender, EventArgs e)
        {
            if (dataGridView1.CurrentRow == null)
            {
                MessageBox.Show("一覧から選択して下さい");
                return;
            }
            DataRow myRow = Database.dataSet.Tables[0].Rows[dataGridView1.CurrentRow.Index];
            myRow.Delete();
        }

保存

DagaGridView の内容がデータベースに反映されます。

        private void buttonSave_Click(object sender, EventArgs e)
        {
            try
            {
                Database.dataAdapter.Update(Database.dataSet, "address");
                MessageBox.Show("保存しました");
            }
            catch (Exception ex)
            {
                MessageBox.Show("失敗しました。" + ex.Message);
            }
        }

まとめ

今回苦労したところは、DagaGridView への操作と、実際のデータとの連携の部分でした。DataSet を無視して DataGridView への追加、削除は簡単に出来たのですが、いざそれを保存しようというところではまってしまいました。

あと、このプログラムで連続して追加や削除を行なって「保存」しようとするとエラーが出る場合があります。DataSet 内の Status の関係だと思うのですが追求してません ^^;)

ソース一式をあげておきます。 -> ここ