Sunday, March 30, 2014

Postgre SQL on a Mac

I'm a Mac user (I know, I know, I should be using Linux) and sometimes there are some differences when using Rails and Ruby. For instance, I was trying to get the Postgre SQL gem to install and it was telling me that it could find the appropriate header files:

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    /Users/username/.rvm/rubies/ruby-2.0.0-p353/bin/ruby extconf.rb 
checking for pg_config... no
No pg_config... trying anyway. If building fails, please try again with
 --with-pg-config=/path/to/pg_config
checking for libpq-fe.h... no
Can't find the 'libpq-fe.h header
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

I did some googling and found that Macports is a useful tool for getting these Postgre SQL headers installed. After installing it and running the commands found on this blog, the bundle install command worked!

Saturday, March 29, 2014

Paper_trail

As I mentioned in my last post, I was looking at using a gem called "paper_trail" to add a kind of "version control" to certain models in our Rails app. I was hoping to implement the undo function as part of a Rails flash message (so when the user clicked "Check-in", a flash message would appear at the top of the page saying that the progress was updated and asking the user if they wanted to undo the check-in if it was a mistake). However, since the progress-bar is in a partial and the update to the progress value is made through an ajax call, I could not get the flash message to return as part of the page's response headers (they got cleared out after the redirect_to call at the end of the method that updates the progress value). Based on the googling I did, I believe this is due to the fact that custom ajax calls do not explicitly retrieve flash message unless you tell them to, and the fact that the progress-bar was in a partial, which made it impossible to display the flash message in the view that was calling the partial. There may be some simple workaround for this issue, but so far, I have not found one.

Thus, I decided to try a different approach. I would use a button to perform the undo (which was probably better than the flash message method since I had to revert the versions of more than one model, which would have been difficult if I had just been using a link in the flash message, since the link would have accepted only one model as an argument). The button would only be display immediately after a checkin occurred and would only remain on the page for about 10 seconds before fading away (preventing the user for undoing an action at a much later point, which could have caused issues with the application). If the user clicked the undo button within that time, it would undo the check-in (reverting the progress and checkin counts) and update the display before fading away.

I had hoped that paper_trail would be able to perform the reverts without any extra updates on my part but, unfortunately, this was not the case. A typical call to revert to a pervious version for a given model (which is stored in a rails instance variable) looks like:

@instance_var.versions.last.reify
@instance_var.save

I had thought that this was working fine for the models that I was having to "undo", but it wasn't. For some reason, when I examined the server requests in the terminal, the paper_trail gem was only updating certain fields during the "rollback". For instance, in one model, it would revert to the previous progress value but not to the previous checkin count value. I am not sure why this is since all attributes of the model are accessible. The only reason I can think of for these issues is the fact that "has_many" and "belongs_to" relationships are not fully supported by paper_trail so I guess this may be influencing the way certain models are reverted based on whether or not they have these relationships. So, I had to do some manual updates to certain models after reverting, but this seemed to work. Now, when the user performs a check-in, they see the undo button as shown below (and the button will fade out after 10 seconds if the user does not click on it).


Friday, March 28, 2014

Client meeting and other things

We had another client meeting yesterday and I think that it went fairly well. We had a demo working so I think this helped a lot since it shows what we've accomplished as well as what we still have to work on. Prof. Ackley brought up some good points, which Fernando put down in a Google doc so we can reference them. One of the suggestions was to change the Success button to be called "Check-in" since this is the term we had been using everywhere else so it made more sense. Fernando and I will also need to add some sort of confirmation modal or popover to the Check-in button so that the user can confirm that they really want to check-in, which should help prevent accidental check-ins on the part of the user. Or, we could figure out a way to "undo" an accidental check-in (one way would be to use the Paper Trail plugin).

This weekend, we plan to have a group meeting to start working on and (hopefully) implementing so basic overall design concepts (color, layout, etc.) so we can have some these for the next client meeting. Have a website that looks appealing, is easy to use, and is fully functioning is going to be very important for the final demo. We have most of the functionality complete so design will be our main focus over the next several weeks.

Fernando and I were able to get the check-in timing/verification mostly complete. The code now allows the user to check-in at any time on the first day of the current week (which is especially important if the challenge has 7 check-ins since, otherwise, the user would not be able to complete all the checkins before the week is up). The code also allows, at most, one check-in per 24 hours since the maximum number of check-ins per week is 7 (which was a design decision on the part of our team). This new code is working with the code that we had added last week, which will have the user retake a week if they miss one or more check-ins for that week. This code was modified slightly to fix a bug that was creating the "redo" week with a start date equal to the end date of the previous week. This was a problem if the user missed some check-ins for a given week and then completely missed the next week. It was also a problem if they had to do 7 check-ins for the week because then they would be "cheated" out of time or else the redo week's start and end times would have already passed if they had missed an entire extra week. Thus, the redo week is now created with a start date equal to the current time to avoid these problems.

Monday, March 24, 2014

Coding session

On Saturday, Fernando and I met with Matt S. and had an impromptu coding session for about 6 hours. Fernando and I were able to get most of the logic for the progress bar complete. This included checking that the user is checking in only once per 24 hours and is completing the requisite number of check-ins per week. This task turned out to be (in my opinion) a little more difficult than expected because it required some logic that would keep track of check-ins on a per week basis. After some brainstorming, Fernando and I decided that this would be best accomplished by creating another model in the database called Week. The purpose of Week was to keep track of how many check-ins the user has done during a week (which is defined based on when the user first started the challenge; so, if the user started the challenge in a Wednesday, then one week is 7 days from the start date, or, in this example, the following Wednesday). Adding this model made it relatively easy to quickly determine if the user is staying on track or whether they are missing check-ins.

Also Fernando and I had put some thoughts and suggestions in a Google doc, which we showed to Matt S. during the coding session, so we could agree on a resolution to the issues. One of these issues was what to do if the user misses a check-in for a given week. We decided that we would not take points away from the user since we want to keep them encouraged. However, we felt that there should be some sort of repercussion, which, in this case, would be to "redo" the week. Since we had implemented the Week model, keeping track of the check-ins and any "redone" weeks was straightforward. However, it was a little trickier to modify the progress bar Javascript code to work with this new penalty system. Since the users' controller was responsible for determining when the user had missed one or more check-ins and then performing the penalty calculations, we had to add some additional Ajax calls to the Javascript code in order to obtain the updated progress and number of check-ins from the controller. Last week, I had added a simple text display below the progress bar, whose function was to simply display the number of check-ins the user had so far completed (out of the total number required for the challenge). This was helpful in debugging the issue that I had mentioned in my previous blog post regarding the display and storage of the progress value. It has also been helpful as we have been debugging the code for validating the check-ins.

So far, we have most of the code working for this check-in validation. We have had to use a compressed timescale for testing this code since obviously it is impractical to continually test these for the "normal" timescale of weeks or months. We have been using 10 seconds to represent a day and 70 seconds to represent a week. However, this compressed timescale also presents its own issues as you have to be very aware of exactly how much time has passed and know when you need to "check-in" in order to test certain features. Using 1 minute to represent a day and 7 minutes to represent a week is a little easier to use for testing, but can get very tedious when you are continually making small changes and then retesting. I have just started using 20 seconds for a day and 140 seconds for a week and this seems to be working fairly well.

While working on getting the new functionality for the progress bar implemented, I learned two things that I should remember for future coding and debugging. First, to print out the value of a variable in Rails, you type:

raise @<variable_name>.inspect

Otherwise you will get an error since it is trying to print out the object, not the object's value. Second, when updating the attributes of a model (which is represented in the current context by an instance variable), you must use either "update_attribute" or "update_attributes" (for updating more than one attribute). You cannot just assign a new value to the attribute by calling "@instance_var.attribute = "some value". I lost about 20 minutes trying to figure out why my code wasn't updating the database before Matt pointed this out. So to do an update of a model's attribute:

@instance_var.update_attribute(:field_name, @instance_var.field_name + <some modifications or updates here such as +, -, etc.>)

There are some more test cases to run through and a few code adjustments to be made, but, overall, the progress bar functionality is mostly complete.

Guest speaker

I found Jeff Van Dyke's talk today in class to be really informative. All semester we have been discussing principles and practices for how to "do" software engineering. Almost all approaches have their pros and cons but it was very interesting to see these principles and conventions put to use in a successful business. I was particularly interested in the use of "small" commits and in the use of the "fudge factor" to encourage developers to become more accurate in their work estimates.

First, regarding commits, I have found that small commits can be quite tricky to do and still maintain a code base that is completely functional and runnable. Depending on the task, it can be difficult to break it up into tasks that you can code in a relatively short period of time (say an hour or two) while still maintaining a fully functional code base. I understand the importance of being able to do small commits, especially, as Jeff mentioned, when you need to "roll-back" the code in order to determine when and where a particular bug or problem was introduced. However, I think it takes a lot of skill and practice to plan out your commits so that you do them frequently enough that they are small, but at the same time, they keep the code base buildable and runnable. I personally have been trying to force myself to do more frequent commits when I am working on a feature or bug, but sometimes I get so caught up in coding that I forget or else I can't seem to figure out a good way to break up the feature's parts so that I commit every few hours. It is definitely something I need to practice more.

Second, the idea of allowing developers to use a "fudge factor" during work estimates is an interesting concept. I was familiar with the practice of adding a certain amount of "padding" to a work estimate, as I have done that at my work as well. I am usually optimistic about how long something will take me so I force myself to add some extra time for the unforeseen problems that inevitably occur. I have been also trying to do this for the Demigod project as well, but this has been harder than I expected because I also have to keep in mind the fact that I am still not an expert in all the tools we have been using so I still have a little bit of a learning curve when trying to do new things with the code. However, using a fudge factor for my estimates would be a good way for me to determine if I am consistently over- or under-estimating how long it takes me to complete a certain task or feature. It would also force me to keep track of my past estimates so I can use those to determine how I am doing.

Wednesday, March 19, 2014

Migrations and more Ajax

I had a pair programming session with Fernando last night where we set up the functionality for storing whether a user challenge has been completed and then marking it as completed on the challenges page (by displaying a Bootstrap glyphicon checkmark next to the completed challenge). However, we still need to decide whether a user should be allowed to retake a challenge or whether it is a "one-time only" thing. I think it might be good to allow users to retake challenges since they may need to do it again to maintain a habit. We also brainstormed about how certain parts of the code should be handled (such as what should happen if the user misses a check-in), which will have to be brought up at our next team meeting so we can make these decisions as a group.

Prior to the coding session with Fernando, I had initially played around with using "rails g migration" to add the boolean "finished" column to the user challenges. This worked well (with code added to the migration file to make sure the default value for finished was "false"). There seems to be a basic convention for performing migrations of different types, which look like the following:

 rails g migration change_data_type_for_progress_in_user_challenge #This is what we used for the boolean.
 rails g migration add_<column_name_here>_to_<table_name>
 rails g migration change_data_type_for_<column_name>_in_<table_name>
 rails g migration remove_<column_name>_from_<table_name>

However, as I was testing this, I noticed an issue with the progress bar itself. For challenges where the duration (times per week * number of weeks) did not evenly divide into 100, the percentage amount for each check-in is (obviously) a decimal value . Since the progress was being stored in the database as an integer, decimal values were being rounded up before being sent to the controller via Ajax. While this will work for small durations or durations that divide evenly into 100, this approach is very, very bad if you want any kind of precision for the progress value. I had initially noticed the problem when I added some text under the progress bar that would tell the user how many check-ins they had completed out of the total number that they had to do. Because of the rounding errors, the check-ins were not adding up (e.g. it would take 15 check-ins to get to 100% instead of 16). Also the rounding errors themselves would compound as the number of check-ins increased.

Therefore, when I met with Fernando last night, we discussed this issue and decided that the best solution was to convert the progress columns in the database (in the histories and user_challenges tables) to decimal values, which can be done with migrations, in particular, the "change" migration, as shown in the migration examples above. We chose to use the "decimal" type instead of "float" because it is more precise and precision is what we need for the progress bar.

Then, after applying the changes to the database, we had to update the Javascript for the progress bar so that it would use and store the decimal value instead of rounding it off. But, when we went to test out the updated code, the decimal value produced by the progress calculations in the Javascript were not being properly saved to the database. Instead they were being truncated prior to saving (i.e. 6.75 would be saved as 6). We used the "raise" keyword in the users controller and "console.log" in the Javascript to try to debug the problem. The Javascript was storing and calculating the value correctly, but when we printed out the Ajax URL and parameters that were being sent to the users controller, we discovered that the progress parameter was being truncated. The URL would contain the correct progress value, but the params[...] array contained only the truncated value of the progress. Since the params[...] array is used to get the progress value and store it in the database, this was where the problem was occurring.

At first we thought that maybe the "." in the decimal value was some sort of reserved character in Ajax. However, this did not make sense because the URL contained a "." and it was parsed just fine (and why would URLs disallow "." since these are used all the time for sending image requests (image.jpg, etc.)). Then we thought that maybe there was some restriction on sending decimal values via Ajax. Again, this did not make sense because I had seen examples where values such as latitude and longitude were passed via Ajax and were not truncated. After nearly an hour of searching through forums, I found a post on stackoverflow.com where another person had had a similar issue. It turns out that this was due to problems with the parameter parsing done server side (not with Ajax). I could not find a way to change this for the Rails server, so I did some more googling and found out that sending the progress via JSON (instead of as a "script") would allow us to prevent Rails from truncating the parameters:

        $.ajax({
          dataType: 'JSON',
          async: false,
          url: "/create_history/" + currProgress,
          data: {"newProgress":currProgress}

        });

Then in the users controller, we can grab the decimal progress value by using params[:newProgress].

Once this problem was solved, we made an update to the Haml and Javascript that displayed the progress bar, adding a hidden congratulations modal that could be displayed using jQuery when the user completed a challenge. We also added a button to the modal that the user can click to take them to the challenges page to find another challenge.

Friday, March 14, 2014

Over spring break...

I felt that our client meeting today with Nikan went well. We were able to successfully demo what we had accomplished and we identified what we needed to get done for the next meeting. I think we have made a lot of progress since our previous client meeting where our demo didn't really work and a lot of the functionality was not complete. 

Over spring break, Fernando and I are going to add a boolean column to the user challenges table that will be true if the user has completed the challenge and false otherwise. Once the challenge completion reaches 100%, the boolean will be set, the user will see a modal dialog that displays a congratulations message, and the user will be given the option to take another challenge. We will also have to mark the challenge as "completed" in the challenges list.

Adding the column to the user challenges table should be as simple as doing

rails g migration AddFinishedToUserChallenge finished:boolean

and then running a "rake db:migrate". Then we just add some extra logic to the progress bar javascript that updates this boolean to true once the challenge has 100% completion. It will probably be a little more difficult to actually mark the challenge as completed and then display the completed challenges in a separate section (called "completed challenges" or something similar) on the challenges page. Obviously the modal that displays the information about the challenge when it is clicked should no longer have the "Take this challenge" button.

We will also have to add a little more logic to make sure that the user is checking in the given number of times per week. Right now, the code is just designed to make sure that the user cannot check-in again until 24 hours after their previous check-in. But, if the user is only supposed to be checking in 3 times per week, we will have to add some code that counts the number of check-ins in a week to make sure the user is staying on track (this information can later be used to send the user "reminder" email messages when they are getting close to missing a check-in). In this case, the first week will start when the user clicks "Take this challenge" (the starting date) and the first week will end seven days from this point. The second week will end 14 days from the starting date and so on. Implementing these checks will be tricky, but the user history table will provide us with timestamps for each check-in so we can use Ruby's handy time features such as 1.minute, 1.day, and 1.week to calculate how much time has elapsed since a given check-in.

Wednesday, March 12, 2014

Ajax and other things

After going through what felt like half of stackoverflow.com and several tutorials on using ajax with jQuery and Rails, I finally figured out how to use ajax to pass an updated instance variable from a controller method to jQuery code in a view. It is so simple I can't believe I didn't figure it out before, but most of the information I found had to do with requesting http, javascript, and json, which was not what I wanted.

Prior to figuring this out, I had been using a hack to get around the fact that the instance variables were only updating on page loads. This was causing issues with the progress bar display because the code could save the updated progress (via ajax) but not access it. Hence I was storing the updated value locally (using an attribute of the progress bar) so that the Success button could be clicked repeatedly and the progress bar would fill up to 100% (which is what we need to demo for the client meeting on Friday). This worked but it wasn't really the right way to it.

Now, using ajax, jQuery can send a GET request to a controller method where the instance variable will be updated from the database and passed back to the jQuery code. Of course, a route also has to be added to the routes.db table so that the url that is given in the ajax call is valid. In the controller method, after getting the desired data from the database, the following render call is made:


render text: @instance_variable

This sends the instance variable back to the calling ajax code where the ajax success property is given a function that gets the requested data and sets it into a jQuery variable:

success: function(data){
    $jquery_var = data;
}

Since the render function in the controller method is passing back text, the data will have to parsed to a float or integer if the value needs to be in a numerical format. However, with just a few lines of code, you can really quickly get updated instance variables from a controller to jQuery code without having to reload the page. This feature is also really helpful to Fernando and I since we will be using timestamps from past user checkins to determine if they are staying "on-track" and will have to get updated information in order to test our code.

As a final note, I had to set "async: false" in the ajax call because ajax (being normally asynchronous) will update the database in the background and the next ajax request in the code to get the updated value might not get the latest version of the value. Thus I set all the ajax calls to be synchronous so that this problem would not happen.


Monday, March 10, 2014

Group coding session + some issues

Since we had to get twice as much done before this upcoming client meeting (due to a miscalculation on our timeline), we decided to meet for an informal group coding session yesterday morning. We all coded pretty much straight from 8:30am to 2:30pm and were able to get the action items mostly completed for this week's client meeting. I think it was good that we all got together and coded up our parts because 1) some parts were dependent on others so you could test them out and get them working without having to wait too long and 2) it gave us all motivation to get as much done as we could. Fernando and I collaborated on updating the progress bar so that it would be able to access the user's current progress on the challenge that they are taking (as stored in the database). There is a table in the database where the user's current challenge is stored as well as table that stores a history of the current challenge. This means that every time the user presses the Success button (to check-in) in order increment their progress in the challenge, a new row is created in the History table with the updated progress value. This allows us to keep track of the user's past check-in times so that we can determine if the user is checking in when they are supposed to.

Currently, the code stores the progress when it is updated and displays the current progress. However, there is an issue with dynamically access the values after the user clicks the Success button once for a page load. After the user clicks Success, the updated progress will get stored in the database and the progress bar will update. However, after the first click, it appears that the instance variables stored in the controller do not get refreshed (since the page is not reloaded) and therefore any additional button clicks will not update the database. Thus, we need to figure out a way (probably using ajax in some form) to call a method in the controller that will reload the updated values from the database for the next click of the Success button.

Additionally, Fernando and I will need to implement code that checks if the user has been checking in regularly as well as checks that they do not check in more than once in a 24 hour period. This should be fairly straightforward since the database date stamps each history row so that you exactly when the user last checked in and can then determine in what time range their next check-in should occur so that they can stay on track.

Friday, March 7, 2014

For next week...

Based on the client meeting today, I think we need to have some good demos to show at the next meeting because I feel that we are falling behind in expectations. We also somehow added an extra week to our timeline, which means that we need to get twice as much done by next week in order to get back on track.

So for the next client meeting, Fernando and I are tasked with updating the progress bar based on information from the user's challenge history. I have a feeling this is going to be a bit tricky because it seems like, from the initial research I've been doing, that there is no consensus on the "best" way to do this. I did find this example which shows three different ways of passing data to Javascript: script tag, data attribute, or a gem called "gon". I am going to try experimenting with using the script tag and the data attribute and see if there is one that seems more appropriate for what we are doing. However, since we are not using CoffeeScript or ERB (embedded Ruby), we are going to have to do some modifications to most of the example code we find since a significant portion of it seems to involve either CoffeeScript or ERB. I also looked at using the gon gem, and it seems like a really simple and straightforward way to get Rails data into Javascript code.

We are also going to have to figure out how to update the user history once the user clicks Success. This is going to be tricky as well since, depending on the type of challenge, we will have to determine whether the user is allowed to update their progress (for instance, if they have to complete a task twice a week, we can't let them click "Success" twice in a row and call it good). Thus, when the Success button is clicked, the code will have to go check the database and determine if the user has already completed their check-in for the day. If they have, then we should put a message stating this. Otherwise, we should update the user's history and update the progress bar. Eventually, we should also probably include some text with the progress bar that reminds the user how many times per week they have to check in, how long the challenge is (duration) and how many times they have already checked in.

Wednesday, March 5, 2014

Struggles with jQuery and Bootstrap

As is usual when coding, things that you think will be "easy" end up requiring the most time. In my case, I decided to do some research on using jQuery to update Bootstrap progress bar since Fernando and were in charge of getting that done this week (along with a few other things). I have some experience in Javascript but almost none in jQuery so I figured I'd better start looking things up early.

So, on Tuesday I spent at least two hours trying to find decent examples of how to use jQuery with Bootstrap. After some searching I found some helpful tutorials and was able to piece together some code that would update the progress bar. However, this code was assuming that the progress bar was a fixed width (measured in pixels) but our progress bar's width is set by percentage, so it is more relative than absolute. I eventually discovered a way around that issue by directly setting the value of the CSS width property for the progress bar element:

var $bar = $('.progress-bar');
var incr = progressValue;
$bar.css('width',incr+'%');

$bar.html(incr+'%');

(I also later found that the "setInterval()" method call that I had seen in many of the tutorials was completely unnecessary since we did not need to continuously animate the progress bar.)

 Anyway, Fernando and I put the above code in a JS method and called it from the "onclick:" property of the button we were using to update the progress bar. We passed in a local variable from the view code to set the value of the progress bar, which in itself it a little tricky because you have to do "onclick: my_function('#{local_var_here}');" (and be sure to include the double quotes). So we reload the code and voila! the button click updates the progress bar. 

However, it would only do it one time per page load. We were using a random number generator for the value so the percentage should have changed with each click but it didn't. We tried using the jQuery "click()" and "on()" methods to attach an event handler to the button but nothing was working. We must have spent at least an hour and half at our pair programming session this morning trying to figure out why it was having this issue. I decided to do some additional research this afternoon and was finally able to figure out a solution. Instead of using "onclick:" to call the Javascript to update the progress bar, I used jQuery .bind('click', function(){...}); to ensure that the function that updated the progress bar was bound to the button we were using. I then used the onclick property of the button to called a JS method that randomly generated a number, which was then used to update the progress bar in the click event handler for the button.

UPDATE: After some additional testing of the progress bar, I found another bug where the button event handler would not fire after a page redirect (though it would still work fine if you just reloaded the page). After some googling, I discovered that you have to use $(document).on('click', '#element_id_here', function (){....}); in order to have the page find and locate the progress bar update button so it can "reattach" the click event handler after a redirect.

But, on the bright side, Fernando and I were able to get one of our other tasks done quite quickly. This task was to pop up a message when a certain button is clicked. We chose to use a small Bootstrap modal, which was fairly easy to implement from the example code on Bootstrap's site.


Monday, March 3, 2014

Second team meeting

We had our second team meeting yesterday for about two hours. During the first part of the meeting, Matt S. made sure that everyone had pulled the new code that he had added on Saturday. This included files and database tables for listing challenges and creating challenges as well as administrator-only pages for viewing and editing users and challenges. I had been struggling to get SourceTree (a Git GUI client for Mac and Windows) to work with the Bitbucket repository (even though, ironically, Bitbucket recommends this app...). I had been able to get SourceTree to commit the changes that Fernando and I made to the code last week, but it refused to pull and merge the changes that Matt S. had made to the code. I finally ended up having to force a merge using Git on the command line, which cleared up the problem.

Once everyone's repositories were up-to-date, we started working on details of our timeline for the remaining weeks of the semester. We had written up a rough timeline at our first meeting, but had not yet gotten it typed up. Matt S. wrote down a list of functionality requirements that we must get done within the next few weeks before we start on design. We then decided who should work on what parts (with Fernando and I teaming up again since our skills in Ruby on Rails is far below that of Matt S. and Matt F. and we have found pair programming to be really helpful with the learning curve). I modified the written requirements of the document in order to put them into a timeline for the group so that each member's action items and the project milestones are listed. This is currently a google doc to which all team members have access so it can be edited and updated as needed.

Fernando and I's current action item for next week is to make the progress bar for the current challenge dynamic so it can updated and to also decide on a naming convention for CSS ids and classes so that we will have a basic convention by the time we get to design. Making the progress bar dynamically update will involve using jQuery, which I've only used a few times (though I have some experience in JavaScript in general) so I am hoping that our coding session will go smoothly. I think the hardest part will be trying to figure out exactly how much the progress bar will update when a user clicks "Success" since the during of a challenge can vary.

Saturday, March 1, 2014

Displaying/Updating images in Rails

As I mentioned in a previous post, installing Paperclip is the first step to being able to display an image in Rails. However, in order to size or scale the image for storage and display, you need to use ImageMagick. If you are on a Mac (as I am), there is a handy package you can download at http://cactuslab.com/imagemagick/. There are other websites with instructions for installing ImageMagick on Linux and Windows machines as well.

Then, assuming you have Paperclip added into your Rails code, add the "styles:" components to the has_attached_file method in the model where you will be storing the image using Paperclip. For example:

  has_attached_file :avatar,
    :styles => {:large => "300x300#"}, 
    :default_url => "avatar_blank.png"

Then open the Rails console by running "rails c" and type the following command to reprocess any images stored in the database prior to the installation of ImageMagick. The command to run is

<ModelNameHere>.find_each{|u| u.avatar.reprocess!}

This will reprocess all the images already in the database and from now on, images uploaded will be saved by the style you gave them. Then, when displaying the image using "image_tag", you can do:

image_tag @<instance_variable_here>.avatar.url(:large)

and display the cropped picture.