Sunday, March 27, 2011

Google Map + RoR

Here I share my experience integrating Google Maps and Ruby on Rails. My platform: Window OS + Rails 3.0.3 + Ruby 1.9.2. There is a bunch of tutorial on how to install the Plug-in for Google Maps in RoR and generate your first map in the RoR.

I followed this tutorial to install the plug-in. I tried the second way of using Github, but it didn't work for me. I got an ym4r_gm folder in my vendor/plugins/ directory, but it was empty. So I used the third way -- manually download the plugin, unzipped the file, put them in the vender/plugins/ym4r_gm. Then copy the javascript/*.js to my public/javascript/ folder. And copy the gmaps_api_key.yml.sample to my config/ folder, renamed as gmaps_api_key.yml

After the installation is done. I didn't apply for the Google Map API key and put it in the gmaps_api_key.yml since I develop and test it in my local machine at current time.
Here is the code:

in the home_controller.rb:

class HomeController < ApplicationController
def index
@map = GMap.new("map_div")
@map.control_init(:large_map => true,:map_type => true)

@map.center_zoom_init([75.5,-42.56],4)
@map.overlay_init(GMarker.new([75.6,-42.467],:title => "Hello", :info_window => "Info! Info!"))
end
end

in the index.html.rb. Because I separate the layout in the application.html.rb, there is only one line in this file.

<%= @map.div(:width => 600, :height => 400) %>


in the application.html.rb
<!DOCTYPE html>
<html>
<head>
<title>Housing</title>
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
<% unless @map == nil %>
<%= GMap.header %>
<%= @map.to_html %>
<% end%>
</head>
<body>
<%= yield %>
</body>
</html>


At the beginning, I didn't realized I separate my layout and content. So I just paste the example on my index.html.rb, but it turns out to be html code in the index.html.rb such as <html><body> becomes plain text, instead of html code. After I realized I actually separate the layout and content in application.html.rb and home.index.rb, I put the code in red lines to the application.html.rb and leave only one line in the home.index.rb

After I have done the things above, I met another problem:
In application.html.rb, when it calls GMap.header, it should print out the Google Map information in the header such as :
<script src="http://maps.google.com/maps?file=api&v=2.x&key=ABQIA..." type="text/javascript"></script>
but the '<' all becomes & lt; , I changed a bit the 'header' and 'div' method in map.rb, using html_safe when it outputs html code. Tell it not to transform '<' to & lt;

The last thing is in the 'header' method of map.rb, "ActionController::Base.relative_url_root"
is said to be a deprecated method, so it could not locate the ym4r-gm.js
So I change

#{ActionController::Base.relative_url_root}/javascripts/ym4r-gm.js

to

/javascripts/ym4r-gm.js

Here are some other useful information:
another tutorial using ym4r_gm and geokit
A tutorial in Chinese (中文)
Geokit

Thursday, March 17, 2011

Saving changes is not permitted -- SQL 2008

When I try to modify a table, for example, change the "allow null" property of a column, or add a new column to the table, I encounter the message like this:


Saving changes is not permitted. The changes that you have made require the following tables to be dropped and re-created. You have either made changes to a table that can't be re-created or enabled the option Prevent saving changes that require the table to be re-created.


It is said that you may change the metadata structure of the table and cause data loss in 'change tracking information'. However, it is so annoying that at the beginning of developmental stage, when the structure of table is subject to change, that we need to re-create the tables.

Here is the way to turn off the feature:
in SQL2008, Tools->Options->Designers->Table and Database Designers
uncheck "Prevent saving changes that require table re-creation".

Microsoft support: see this

StoredProcedures

Recently, I start to use MS-SQL StoredProcedures instead of hard-coding SQL query in the program. Using StoredProcedure is a good way of separating database queries and ASP.NET code. However, there is slight difference. For example, I want to execute a query like the following:

using (SqlConnection conn = new SqlConnection(connStr))
{
SqlCommand cmd = new SqlCommand("select * from Employee where eid in (15,16,17)", conn);
conn.Open();
SqlDataReader rs = cmd.ExecuteReader();
GridViewResChanged.DataSource = rs;
GridViewResChanged.DataBind();
}

It works perfectly. But if I want to send '(15,16,17)' as a varchar parameter to the StoreProcedure, then it failed:

using (SqlConnection conn = new SqlConnection(connStr))
{
var eids = '(15,16,17)';
SqlCommand cmd = new SqlCommand("queryEmployee", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@eids", SqlDbType.VarChar).Value = eids;
conn.Open();
cmd.ExecuteNonQuery();
}

It is said to be insecure if web users maliciously insert a random string into the database server:
How to pass a list of values or array to SQL Store Procedures

If I insisted using StoreProcedures, I need to learn how to loop the string and get those comma-separated input out in T-SQL.
It is sometimes pain in the ass when the code works perfectly before but failed in a new way of implementation.

Wednesday, March 9, 2011

empty string -- ASP.NET textbox

When I work with TextBox in C# ASP.NET, empty string in TextBox cause problems when it is an input to the sql queries. Because TextBox.Text does not return null value while the textbox is empty.

Empty text is converted to null value in default configuration as I use "SqlDataSource" connection string. But when I need to tackle this manually, here is a handy way:

TextBox tb;
String value = String.IsNullOrEmpty(tb.Text) ? null:tb.Text;

value is the new input to the database.

Tuesday, March 8, 2011

copy StoredProcedures between servers

MS-SQL Stored Procedures is one way that we don't need to ugly hard-code the SQL queries
in the program. However, recently, we have several versions of database update. To export procedures in old database to the new one:

In Microsoft SQL Server Management Studio, Object Explorer,
right-click on the stored procedure, select "Script Stored Procedure as CREATE TO", then either save the stored procedure as a SQL file or create a new SQL window and execute the query file in the new database. After the execution, the stored procedure is created in the new database.
But one thing to be noticed: in the head of the query file, if the names of databases are different,
then the database name need to be changed in "USE [database_name]".

Monday, March 7, 2011

create an overlay on top of an image



recently, while I am editing my web page of project description, I was thinking of creating an overlay on top of the image. It is a feature commonly seen in web pages nowadays.


lets say, we have one outer div, two overlay div, and one image. The overlay divs are smaller and contained in the outer div.

<div class="outer">
<img src="some.png" alt="image" />
<div class="overlay" id="overlay1">This is an overlay1</div>
<div class="overlay" id="overlay2">This is an overlay2</div>
</div>


then set the CSS as:

div.outer
{
width: 570px;
height: 420px;
position: relative;
float: left;
}

div.overlay
{
position: absolute;
opacity: 0.5;
background-color: green;
}

#overlay1
{
left: 20px;
top: 20px;
width: 100px;
height: 40px;
}

#overlay2
{
left: 150px;
top: 100px;
width: 80px;
height: 30px;
}

the most important thing, is the overlay div "position: absolute" and the outer div "position: relative".