Thursday, May 31, 2012

Multiple rails apps on a single server using RailsBaseURI

So after struggling with this for quite some time here is the configuration that works for me to host multiple rails apps on a single server using RailsBaseURI. Before we get into this, you need to be comfortable setting up a typical production rails server. See THIS POST for that.

OK, so if you followed my previous post, you already have one app, so you need to create a 2nd app. After you have done that we not need to edit you apache config file in /etc/apache2/httpd.conf. So I have two apps that are in my home folder. The apps are task_app and calculator_app, and there paths are /home/ubuntu/task_app and /home /ubuntu/calculator_app. We will be using the RailsBaseURI and you can find documentation for this HERE. So, adding the RailsBaseURI options for each of my apps, I now have this in my apache config file...

   LoadModule passenger_module /home/ubuntu/.rvm/gems/ruby-1.9.2-p320/gems/passenger-3.0.12/ext/apache2/mod_passenger.so
   PassengerRoot /home/ubuntu/.rvm/gems/ruby-1.9.2-p320/gems/passenger-3.0.12
   PassengerRuby /home/ubuntu/.rvm/wrappers/ruby-1.9.2-p320/ruby
<VirtualHost *:80>
    Alias / /var/www/index.html

    ServerName www.hezekiahroad.com
    DocumentRoot /home/ubuntu
    <Directory /home/ubuntu>
        Allow from all
    </Directory>

    RailsBaseURI /task
    <Directory /home/ubuntu/task_app>
        Options -MultiViews
    </Directory>

    RailsBaseURI /calc
    <Directory /home/ubuntu/calculator_app>
        Options -MultiViews
    </Directory>

</VirtualHost>

Next we need to add sym links in the document root folder (in my case my home folder) that point to the app/public folder of each app. So I executed...

' ln -s calculator_app/public/ calc' and 'ln -s task_app/public/ task'



We can name these sym links anything we want, but the name of the symlink is the sub uri that the user will navigate to for each out so for the calc app the user will got to www.yourserver.com/calc and for the tasks app it will be www. yourserver.com/task.

Also notice I added the line ' Alias / /var/www/index.html' in the apache config file. If you do not add this, then when the user visits the root of the url (www.yourserver.com) then they see your applications folder structure. We don't want this, so here I have creating an alias for '/' (which is the url root) and redirecting it to /var/www/index.html which is the apache 'it works' file, but you can redirect this to where ever you like.

Soooo...with all that done, you should be able to reboot your server and visit www.yourserver.com/calc and see your calculator app (or whatever app you have in that location) and also visit www.yourserver.com/task and see your task app. And when you visit the root url, you should see the html file your alias points to.

Hope this helps some folks out. Good luck!

Wednesday, May 30, 2012

AWS Ubuntu 12.04, apache and rails production server

>Load Ubuntu 12.04. I get all my base images from http://alestic.com/ You can choose the AWS region on the right pane. If you are using the free tier and don't want to incur any fees use the EBS boot so you can spin up a micro instance.

>Get updates and a few other nick nacks. Run 'sudo apt-get update' and 'sudo apt-get upgrade' Also I like to be able to login remotely to my server without the key so I allow remote login by going into /etc/ssh/sshd_config and set 'setpasswrd = yes'. Then restart ssh with 'sudo service ssh restart'. Now set your users password with 'sudo passwd ubuntu'.

>Install RVM ruby and rails Run 'curl -L get.rvm.io | bash -s stable'. This will probably fail. You need a few packages before rvm can run. Read the output in the error message and there is a section that lists a much of packages. Simply cut/paste this section into the terminal to install them. After this is successful you need to source rvm with 'source ~/.rvm/scripts/rvm', and now install your ruby version of choice. I installed 1.9.2 with 'rvm install 1.9.2'. Now that you have ruby you can 'use' that version by typing 'rvm use 1.9.2' and now you can install rails with 'gem install rails'.

>Install apache
 To install apache type 'sudo apt-get install apache2' Now if you navigate to your web the server in your browser you should see the cheezy 'It Works' massage from apache. Keep in mind you need to open port 80 on you AWS server.

>Install passenger
Run 'gem install passenger'. After the gem installs run 'passenger-install-apache2-module' the install will run and it will probably tell you that you are missing some stuff. So just install that stuff. In my case I need 'sudo apt-get install libcurl4-openssl-dev apache2-prefork-dev libapr1-dev libaprutil1-dev'. So after that stuff installs, run 'passenger-install-apache2-module' again. After passenger installs  DON'T CLEAR THE SCREEN!!! You need to copy the LoadModule statement and paste that into your /etc/apache2/httpd.conf file.

>Create a rails app
OK, we have all this cool configuration, now how do we wrap it all up with a rails app. OK, lets create one, but before we do we are in production now, so lets install a real database. Run 'sudo apt-get install mysql-server'. No, its not postgres, which is a REAL database, but it will do. MEEEOW...give that kitty a bowl of milk! OK, now lets create a rails app, and we will make mysql our default DB. Lets run 'rails new task_app -d mysql', and cd into that directory and go ahead and add 'gem therubyracer' to the Gemfile and run bundle (why do I have to do that?).  Also before I can run any rails scaffold commands I have to run 'export RAILS_ENV=production' why do I have to do this?

Sooo, now we can run some scaffolding 'rails g scaffold task name importance:boolean'

OK, if we check out app/config/database.yml we see the mysql configuration from our app, and it has given us a default name of 'task_app_production'. So lets run 'rake db:create' and 'rake db:migrate'.

Now we need to add this to our apache config file in /etc/apache2/httpd.conf

   LoadModule passenger_module /home/ubuntu/.rvm/gems/ruby-1.9.2-p320/gems/passenger-3.0.12/ext/apache2/mod_passenger.so
   PassengerRoot /home/ubuntu/.rvm/gems/ruby-1.9.2-p320/gems/passenger-3.0.12
   PassengerRuby /home/ubuntu/.rvm/wrappers/ruby-1.9.2-p320/ruby

<VirtualHost *:80>
    ServerName www.yourserver.com
    DocumentRoot /home/ubuntu/task_app/public
    <Directory /home/ubuntu>
        Allow from all
    </Directory>
</VirtualHost>

..and one more thing before we lock and load. We need to go in to config/environments/production.rb and set 'config.assets.compile = true' rather than 'false'. Now restart apache with 'sudo service apache2 restart' and you should be good to go!











See this post for running multiple apps on a singe server.

Thursday, November 17, 2011

A user managment console for devise

I have an app I am working on where I need to give users of my app the ability to create other users in the system. I am not sure of the author of this article, but many thanks for this blog post:

http://zyphmartin.com/blog/manage-users-with-devise-and-cancan

There is a github repo linked in this article that gives an excellent example of a user console for devise. The original repo used mondodb, so I forked the project and made modifications so the app would use standard sqlite, with a few of my own tweaks. Here is a link to the forked project:

https://github.com/marklocklear/devise-roles-user-management

Monday, November 14, 2011

Devise: User belongs_to organization

Devise is the most awesomist (yes, its a word) authentication plugin for rails. I have a scenario where, when the user registers they can also enter an organization. I have a clinical application where there is an admin who will have the ability to create users, so the initial user who creates an account (and an org) will then be able to create users who will also be associated with that org. Also, I wanted to do this without adding, modifying the devise registration controller.

Enough talk, heres the code. If you need tips on getting started with devise check out Ryan Bates screencasts here:

http://railscasts.com/episodes/209-introducing-devise http://railscasts.com/episodes/210-customizing-devise

Here are my models: https://gist.github.com/1336517

Couple things to note here. I think the belongsto and nestedattribs is pretty straightforward. However, also note the :organizationattributes added to attraccessible.

Here is my view: https://gist.github.com/1336513

Create multiple models in a single form without nested attributes

So I am surprised that Rails does not give you an easy way to create multiple models in a single form without the use of nested attributes. Ryan Bates does an excellent job of explaining Nested Models, and the creation of multiple models in a single for in his Railscasts part 1 & 2. Incidentally, if you are looking for a Rails 3 version of this app check THIS out.

First, lets look at the rather trivial case of simply entering multiple models in a single form. Lets says we have a small survey application, and we want to enter a number of questions into the survey. Using standard scaffolding Rails will only allow us to create one question at a time. In THIS app I have modified the controller and view which allows the user to enter 3 questions at a time. This code of a rehash of code presented in THIS forum post.

…but lets consider another use case:

Since this is a Survey application we will want to enter results for each question, so lets have Question and Result models. Question hasmany :results, and Results belongsto :question. This sets up the classic scenario where we would want to use acceptsnestedattributesfor. However, acceptsnestedattributesfor is typically used for ‘creation’ of multiple models at the same time, on the same form. Lets consider a use case where we have pre-existing Question data, and we want to create/associate a Result with a Question AFTER the creation of the Questions. So, we will enter our questions using the standard rails forms, but the twist comes when we go to enter our results. Let say for however many Questions we have in the app, lets display them on the screen, and allow the user to enter a score for each question. For our purposes we will say our ‘score’ will simply be a number between 0 and 4, and will will display a radio button for each number. This is tough nut to crack, and let know one tell you otherwise! This will require use to gather all the questions and put them in an array. Then for each question we will ‘build’ a result. This will ensure the association between the result and question is put in place (ie, we save the questionid in the result). We will do this in the results controller and view. So lets look at that code…
results controller

def new @results = Array.new @questions = Question.all @questions.each do |q| @results.push q.results.build end end

Next, in the view we need to display each question name, and its associated radio buttons..
app/views/result/form.html.erb

<%= formtag :action => ‘create’ %> <% @results.eachwithindex do |result, index| %>

<%= fieldsfor “results#{index}”, result do |f| %> Queston:<%= @questionsindex.name %> <%= f.hiddenfield :questionid%> <%= f.radiobutton :score, ‘0’ %>0 <%= f.radiobutton :score, ‘1’ %>1 <%= f.radiobutton :score, ‘2’ %>2 <%= f.radiobutton :score, ‘3’ %>3 <%= f.radiobutton :score, ‘4’ %>4 <% end %> <% end %>

<%= submittag ‘Submit’ %>

I’d love to say I know everything that is going on in this code, but I don’t, so some chime in with a nice step-by-step explanation of what’s going on and I will post it. Same goes for the create action in the controller code…

def create @results = params:results.values.collect { |result| Result.new(result) } if @results.all?(&:valid?) @results.each(&:save!) redirectto :action => ‘index’ else render :action => ‘new’ end end

You can check out the app HERE https://github.com/marklocklear/multiple_models_one_form

Someone respond with an explanation of views and create actions. Thanx!

How to add your json file to you sqlite database, aka seed your db

If you are using rails and have data in json format that you want to add to your database you want to use the ‘rake db:seed’ task to do this. So lets say my json data looks like this:

{“idnumber”: “00xx76”,”username”: “suiuk”,”firstname”: “Rue”,”lastname”: “Ouk”,”email”: “Siuk@wintas.edu”,”phonenumber”: “333-555-1921 ext 191”,”isactive”: true ,”lastfour”: “7001” }, {“idnumber”: “00xx552”,”username”: “ronyne”,”firstname”: “Rond”,”lastname”: “Lne”,”email”: “rerte@wintas.edu”,”phonenumber”: “444-555-1921 ext 334”,”isactive”: true ,”lastfour”: “3668” }

Here is what my db/seeds.rb file will look like…

json = ActiveSupport::JSON.decode(File.read(‘db/tests.json’)) json.each do |a| Test.create!(:idnumber => a‘idnumber’], :username => a‘username’, :firstname => a‘firstname’], :lastname => a‘lastname’], :email => a‘email’, :phonenumber => a‘phonenumber’], :isactive => a‘isactive’], :lastfour => a‘lastfour’],) end

..and for good measure here is the what the db schema looks like…

sqlite> .schema tests CREATE TABLE tests(idnumber integer, username string, firstname string, lastname string, email string, phonenumber string, isactive boolean, lastfour string);

Now to run this do ‘rake db:seed’ Also, be sure you have a model (app/model/yourstuff.rb) that accompanies the table in the database. I was playing around with this in the beginning and I kept getting the error ‘Uninitialized Constant’ until I created the model code.