Wednesday, December 18, 2013

Installing Ruby on Rails in Ubuntu 12.04 on Azure

In previous posts, I covered installing Ubuntu on Windows Azure, remotely accessing Linux from Windows Azure, installing LAMP and installing Git on Linux and a few other topics. The next subject I’ll be writing about is the Ruby on Rails web development platform.

There are some great resources out there for learning Ruby and Rails, and when the install goes smoothly, it’s very easy. I’m not an expert on Ruby, but the install didn’t go swimmingly for me, so I’m writing this post.

Step 1 – Install RVM and Ruby

\curl -L https://get.rvm.io | bash -s stable --ruby

Ruby Version Manager (RVM) is a great tool for working with Ruby. You can even run multiple versions of Ruby and easily switch back and forth.

image

Step 2 – Install Rails

Finally, you can use RubyGems to install rails:

gem install rails (may need sudo, I had to run it with both, see note below)

Note: if you see the error, ERROR:  Error installing rails: activesupport requires Ruby version >= 1.9.3.”, (or some other version) install Ruby 1.9.3 (Yes, even if you have a newer version installed) then use RVM to set the old version as the default using: rvm use ruby-1.9.3. This caused me much angst today. You can use ruby –v to see which version you’re running and rvm list to see the installed versions.

I also ran into this ugly error:

cawood@cawood:~$ rails --version
/usr/lib/ruby/1.9.1/rubygems/dependency.rb:247:in `to_specs': Could not find railties (>= 0) amongst [activesupport-4.0.2, atomic-1.1.14, bigdecimal-1.1.0, bundler-1.3.5, bundler-unload-1.0.2, executable-hooks-1.2.6, gem-wrappers-0.9.2, i18n-0.6.9, io-console-0.3, json-1.5.5, minitest-4.7.5, minitest-2.5.1, multi_json-1.8.2, rake-0.9.2.2, rdoc-3.9.5, rubygems-bundler-1.4.2, rvm-1.11.3.8, thread_safe-0.1.3, tzinfo-0.3.38] (Gem::LoadError)
        from /usr/lib/ruby/1.9.1/rubygems/dependency.rb:256:in `to_spec'
        from /usr/lib/ruby/1.9.1/rubygems.rb:1210:in `gem'
        from /usr/local/bin/rails:18:in `<main>'

I had to run gem install rails (with no sudo) to get all the gems to install properly. After I did that, I could see that Rails was installed properly:

cawood@cawood:~$ rails --version
Rails 4.0.2

Of course, my list of installed gems was much longer because the missing gems had been installed. It should look like this:

cawood@cawood:~$ gem list

*** LOCAL GEMS ***

actionmailer (4.0.2)
actionpack (4.0.2)
activemodel (4.0.2)
activerecord (4.0.2)
activerecord-deprecated_finders (1.0.3)
activesupport (4.0.2)
arel (4.0.1)
atomic (1.1.14)
bigdecimal (1.1.0)
builder (3.1.4)
bundler (1.3.5)
bundler-unload (1.0.2)
erubis (2.7.0)
executable-hooks (1.2.6)
gem-wrappers (0.9.2)
hike (1.2.3)
i18n (0.6.9)
io-console (0.3)
json (1.5.5)
mail (2.5.4)
mime-types (1.25.1)
minitest (4.7.5, 2.5.1)
multi_json (1.8.2)
polyglot (0.3.3)
rack (1.5.2)
rack-test (0.6.2)
rails (4.0.2)
railties (4.0.2)
rake (0.9.2.2)
rdoc (3.9.5)
rubygems-bundler (1.4.2)
rvm (1.11.3.8)
sprockets (2.10.1)
sprockets-rails (2.0.1)
thor (0.18.1)
thread_safe (0.1.3)
tilt (1.4.1)
treetop (1.4.15)
tzinfo (0.3.38)

Alternate Method—This didn’t work for me on Ubuntu 12.04

Step 1 – Install Ruby

You can either install the standard version: sudo apt-get install ruby-full build-essential
or the minimal requirements with: sudo aptitude install ruby build-essential libopenssl-ruby ruby1.8-dev (note the version number – you’ll have to update that).

I’m going with the first option to install ruby-full.

image

Step 2 – Install the Ruby Version Manager

CAUTION: Normally you would just run: sudo apt-get install ruby-rvm

However, there is an issue with the Ubuntu RVM package, so you should run this instead: \curl -L https://get.rvm.io | bash -s stable --ruby --autolibs=enable --auto-dotfiles

If you do run into issues with RVM. For example, using rvm use doesn’t change to the version you want, you can run these commands to clean your system (see this thread).

sudo apt-get --purge remove ruby-rvm
sudo rm -rf /usr/share/ruby-rvm /etc/rvmrc /etc/profile.d/rvm.sh


Then, open new terminal and validate environment is clean from old RVM settings (should be no output):



env | grep rvm


Step 3 – Check that You’re Using the Latest Version of Ruby



ruby –v will show you which version you’re using.



If you’re not using the one you want, you can use RVM to upgrade. This will download the source that is then used by RVM in the next step to compile and install Ruby; it is not a quick command.



sudo rvm install ruby-1.9.3-p125



or



sudo rvm install ruby-1.9.3 (Note version number)



However, if you do the second option, you may need to workaround an issue before updating. If you try to install ruby-1.9.3, you might get the error: “ERROR: The requested url does not exist: 'ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-.tar.bz2' from RVM. You can workaround this by downloading the package yourself.”



sudo curl -o /usr/share/ruby-rvm/archives/ruby-1.9.3-.tar.bz2 \http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p0.tar.bz2



Check that you’re using the latest Ruby: ruby -v

If not, switch to the latest using RVM: rvm use 1.9.3



Step 4 – Install Rails



Finally, you can use RubyGems to install rails:



sudo gem install rails



Step 5 – Install a Web Server



I use Apache and MySQL, so the LAMP install works for me, but there are other options such as WEBrick or Lighttpd.






Other posts on this topic:


RubyOnRails.org getting started


Ubuntu documentation – Ruby on Rails


Thursday, December 05, 2013

Using Wyzz Web-based HTML editing control in ASP.NET MVC

I recently had to put out a web-based single page application (SPA) on short notice. To make that happen, I knew I had to use some open-source controls. One was the jsTree treeview control (which I wrote about on this blog - Using jsTree with ASP.NET MVC) and another was the Wyzz WYSIWYG web-based editing control for HTML.
From their site, “Wyzz is an ultra-small, very light WYSIWYG (What You See Is What You Get) Editor for use in your web applications. It's written in JavaScript, and is free (as in speech and as in beer) for you to use in your web applications and/or alter to your needs (see the license conditions).
image
Naturally, the first step to add a reference to the wyzz.js script file. Once you have that, you just need to add the control to an HTML <textarea> element. Finally, it’s a simple matter of adding some JavaScript to “make_wyzz” the control.
<script language="JavaScript" type="text/javascript" src="~/Home/wyzz.js"></script>



<textarea name="textEditor" id="textEditor" rows="10" cols="40">No file loaded...</textarea><br />
<script language="javascript1.2">
    make_wyzz('textEditor');
</script> <div ng-controller="EditorCtrl"> <form novalidate class="simple-form"> <button ng-click="saveFileContent()">save</button> </form> </div>

As you can see in the example above, I’ve chosen to use an AngularJS control to define the behaviour of the save button. In the JavaScript I define a server-side controller function (ASP.NET in this case) and I send it the content of the control by accessing the HTML element that the control is using.

$scope.saveFileContent = function () { 
        $http.post('/Home/SaveFileContent', { filePath: document.getElementById("multilingualfile").innerHTML, content: document.getElementById("wysiwyg" + "textEditor").contentWindow.document.body.innerHTML, title: document.getElementById("titleHtml").value })
            .then(
            function (response) {
                alert("File Save Result: " + response.data.Result);
            },
            function (data) {
                alert("Error saving file content");
            }
        );
    }

Update: Here’s the basic format of the server-side part:


[HttpPost]
public ActionResult SaveFileContent(string filePath, string content, string title)
{
    try
    {
        ...
        
        return Json
            (
                new
                {
                    Result = "Success",
                }
            );
    }
    catch (Exception ex)
    {
       ...

        return Json
            (
                new
                {
                    Result = "Error saving content: " + ex.ToString(),
                }
            );
    }
}

To customize your Wyzz controls, you can edit the wyzz.js file. If you have any issues, refer to the Wyzz discussion forum.

Sunday, December 01, 2013

Using jsTree with ASP.NET MVC

When I wanted to use a pure JavaScript treeview control for a recent ASP.NET MVC5 project, I looked around and found jsTree; it’s a popular and rich solution, so I decided to try it. I ran into a few customization hurdles, so here are my lessons learned.

Note that this is for jsTree 1.0; at the time of writing, 3.0 has not been released.

Step 1: The HTML in the view. Pretty simple…

<div id="FileTree"></div>


Step 2: Loading the tree dynamically from the MVC controller using jQuery.

<script type="text/javascript"> 
// Begin JSTree: courtesy Ivan Bozhanov: http://www.jstree.com:

$('#FileTree').jstree({
"json_data": {
"ajax": {
"url": "/Home/GetTreeData",
"type": "POST",
"dataType": "json",
"contentType": "application/json charset=utf-8"
}
},
"themes": {
"theme": "default",
"dots": false,
"icons": true,
"url": "/jstree/themes/default/style.css"
},

"contextmenu": {
"items": {
"create": false,
"rename": false,
"remove": false,
"ccp": false,
}
},

"plugins": ["themes", "json_data", "dnd", "contextmenu", "ui", "crrm"]
})

</script>


Step 3: Server-side code to populate the tree. This code is based on desalbres’s Simple FileManager with jsTree. (The model code is below.)

// Begin JSTree (Controller code courtesy desalbres: http://www.codeproject.com/Articles/176166/Simple-FileManager-width-MVC-3-and-jsTree)
[HttpPost]
public ActionResult GetTreeData()
{
if (AlreadyPopulated == false)
{
JsTreeModel rootNode = new JsTreeModel();
rootNode.attr = new JsTreeAttribute();
rootNode.data = "Root";
string rootPath = Request.MapPath(dataPath);
rootNode.attr.id = rootPath;
PopulateTree(rootPath, rootNode);
AlreadyPopulated = true;
return Json(rootNode);
}
else
{
return null;
}
}

/// <summary>
/// Populate a TreeView with directories, subdirectories, and files
/// </summary>
/// <param name="dir">The path of the directory</param>
/// <param name="node">The "master" node, to populate</param>
public void PopulateTree(string dir, JsTreeModel node)
{
if (node.children == null)
{
node.children = new List<JsTreeModel>();
}
// get the information of the directory
DirectoryInfo directory = new DirectoryInfo(dir);
// loop through each subdirectory
foreach (DirectoryInfo d in directory.GetDirectories())
{
// create a new node
JsTreeModel t = new JsTreeModel();
t.attr = new JsTreeAttribute();
t.attr.id = d.FullName;
t.data = d.Name.ToString();
// populate the new node recursively
PopulateTree(d.FullName, t);
node.children.Add(t); // add the node to the "master" node
}
// loop through each file in the directory, and add these as nodes
foreach (FileInfo f in directory.GetFiles("*.htm"))
{
// create a new node
JsTreeModel t = new JsTreeModel();
t.attr = new JsTreeAttribute();
t.attr.id = f.FullName;
t.data = f.Name.ToString();
// add it to the "master"
node.children.Add(t);
}
}

// Don't load the jsTree treeview again if it has already been populated.
// Note: this causes a bug where the tree won't repaint on browser refresh
public bool AlreadyPopulated
{
get
{
return (Session["AlreadyPopulated"] == null ? false : (bool)Session["AlreadyPopulated"]);
}
set
{
Session["AlreadyPopulated"] = (bool)value;
}

}
// End JSTree

First I had to resolve the issue that a browser refresh would repaint the whole treeview. It’s possible that I simply missed this when I cherry picked code from the FileManager codeproject example.


public ActionResult Test(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
Session["AlreadyPopulated"] = false;
return View();
}

Next, I had to customize jsTree the way I wanted it to behave. Getting the tree to start collapsed (closed) instead of expanded (open) was the first order of business. The jsTree API took care of the problem.


$('#FileTree').bind("loaded.jstree", function (event, data) { 
$(this).jstree("close_all");
})


Next, I wanted the leaf nodes to use a different background image than the folder nodes. This required changing the server-side code to actually write the leaves (files) as leaf nodes and then add the right CSS to style the jstree-leaf class.



namespace FileEditor.Models 
{
public class JsTreeModel
{
public string data;
public JsTreeAttribute attr;
// this was "open" but changing it to “leaf” adds “jstree-leaf” to the class
public string state = "leaf";
public List<JsTreeModel> children;
}

public class JsTreeAttribute
{
public string id;
}
}


And then styling the leaf nodes with a different background image than the folders.



<style type="text/css"> 
#FileTree .jstree-leaf > a > ins {
background: url("/jstree/themes/default/d.gif");
background-position: -2px -19px !important;
}
</style>


Finally, I wanted to disable the right-click context menu options since I’m not using them. (This code appears in the code above.)

"contextmenu": {
"items": {
"create": false,
"rename": false,
"remove": false,
"ccp": false,
}
},

That’s it. jsTree is not working the way I want. I expect that version 3 will be great when it is released.

Other posts on this topic:
jsTree – Few examples with ASP.Net/C#
Simple FileManager width MVC 3 and jsTree