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.