Assignment 3, Milestone III

 


25-Nov-2008: See note on datetime_select here: http://e168f08.plugh.org/uncategorized/datetime_select-used-in-assignment-3/

A version of this doc is in the download’s README file, but this version is official; any tweaks or changes will be given in dated updates at the top.

Assignment 3, Milestone III: Controllers and Views
Due date: Sunday, Dec. 7

In Assignment 3, Milestone III, you will modify MetricMine, adding controllers and views.

There are some small changes between this version and the prior version: 20081111021247_add_current_observation_set_id_to_user.rb adds a column to user “current_observation_set_id” - whenever you view an observation set, the id is saved here so that when you log in from a cookie, you can be redirected to that set: This makes it especially easy to enter a new observation for whatever set you were last looking at. There are also some extra validations on the models; these changes required some tweaks to the tests (we didn’t add tests for the additional validations, but we did need to change our existing tests). We added a default value of ” for the notes field on observations. We also added a “dependent” option for ObservationKind so that when it is deleted, the foreign key will be set to null on any ObservationSets that belong to it. Finally, there is an additional data migration so that the “john” user has two relatively detailed observation sets (for weight and savings).

About nomenclature:

In the UI, an observation set is called a metric, and an observation kind is called a “kind of metric” or a “metric kind.” It seemed to us that for the end user this language is easier that observation/observation set.

Now, what are you supposed to do?

You need to flesh out the controllers and views that manage certain models for basic CRUD operations.

Any time you like, you may play with a “reference implementation” here:

http://metricsmine.plugh.org/

We will re-run the migrations periodically to clear out the database.

Also note that you can fire up your server (ruby script/server), browse to http://localhost:3000, and quite a bit of MetricsMine will run. You will see some missing data because your controllers aren’t finished, or some static data that doesn’t apply to your user, because the views aren’t all dynamic. In a number of cases, we have marked out views that need to be made dynamic; in some cases, we give you some static rendered HTML that is the result of the reference view code. All of this is to alert you to what must be done.

Regarding the static HTML: Remember that almost all of this is generated dynamically! E.g., if the action on a form is to “/observation_sets/create_observation” that is probably generated with something like this:


<% form_for :observation, :url => { :action => :create_observation } do |form| %>

In other words, USE YOUR VIEW HELPERS! We don’t want to see “raw” HTML links, form actions, etc., etc. Such things will count against you.

For controllers, make sure that you choose redirect or render properly; we will mention this occasionally below, but the behavior should be like the reference MetricsMine application. When this assignment is graded, we will spot-check for this. In the views, there are a number of little details you need to get right: The page title; the error display (both summary and per-fiend); setting the focus on the first element for a field; etc. Again, graders will spot-check, so you need to get this right everywhere.

NOTE: On occasion, you may see an error message claiming that there is no template for the “create” (or another) action. Remember that in Rails, we typically redirect after create, or use the view template for another action; in other words, these error messages may be spurious, depending on where you are with the assignment. When in doubt, review the reference implementation.

This download includes a fully-migrated version of the database. If you want to get the database back to its original condition, do


rake db:migrate VERSION=02
rake db:migrate

During development, you may also find that you need to delete any permanent cookies in your browser for the app associated with the “localhost” server. You would want to do this if the saved user id is forcing you to an action + view you haven’t implemented yet.

Let’s go through the actions, roughly by controller:

(1) The easy cases: Administrative functions. Remember that you have to log in as “admin” to see these. You should be able to finish these swiftly; within 4 hours, maximum.

Controllers:

MeasurementsController
ObservationKindsController
UnitsController

These are roughly the same as the CRUD operations in LinkWizz, CCC, and LinkWizz’s ResearchTopicsController. Remember that a Unit belongs to a Measurement (same for ObservationKind), so for edit and new you will need to set up a @measurements instance variable that holds the options for the drop-down.

Notice that you CAN delete an ObservationKind.

Views:

For each of these controllers, there are views for edit, index, and new - there is no “show” because the relevant data is shown in the list. A pattern you may see is to implement a “list” action, and have the “index” action utilize it; in MetricsMine we’ve simply implemented index.

We have included STATIC stubs for the views for ObservationKinds to give you a feel for what the rendered dynamic view should look like (you can do “view source” on the reference implementation to see the same sort of thing). Notice the fancy JavaScript for the “(delete)” link. The view helper link_to’s :action => ‘destroy’ option will do all of this for you.

For the others, we have just included a message asking you to implement the view.

(2) Managing an Observation Set and its Observations

This will be more difficult. There are a lot of little details here. Try to get as far as you can; we will give you hints on the discussion board, particularly if it is clear that you are making headway.

Controller: ObservationSetsController

Notice that this controller manages updates of BOTH ObservationSet and Observation. This is not an unusual pattern. Since Observation is almost completely a “slave” of ObservationSet, it is convenient to manage both Models in the same controller. When we get to REST, we will talk about changing this.

Actions

new and create: The new and create paired actions are for creating a new ObservationSet. Notice that you cannot edit/update the name and kind of a user’s ObservationSet!

NOTE: When an ObservationSet is created, don’t forget to (a) set the @observation_set’s user_id to that of the current user, and (b) also set the @observation_set’s preferred unit to the first unit of the selected ObservationKind’s Measurement!! These two items (a) and (b) are each easily expressed in a single statement.

show: This shows all of the observations for the observation set, AND it sets up a form for adding a single observation! When an observation set is displayed or edited, the current observation set id is copied to the current user’s attribute current_observation_set_id. You must do this as well. This allows the filter on the application controller to bring the user back to the last observation set edited, for easy addition of new data.

create_observation: This is the action to which “show” posts when you want to create a single observation. Let me repeat: *NEW* sets up the form for an observation_set that posts back to *CREATE* to create an observation_set. But *SHOW* shows all the observations, AND sets up a form for an observation; that form posts back to *CREATE_OBSERVATION*. In the reference implementation, the id of the newly-created observation is put into the flash, so that when the list of observations is re-displayed, we can change the background color of the row. You need to do this, too; to get it to happen you will want to dynamically change the style element on the correct <tr> tag. E.g., it would look like:

<tr>

when the row shouldn’t be emphasized; and

<tr style=”background-color: #E0FFFF”>

when it should be emphasized. This is the sort of thing you can glean from view/source for the reference implementation.

edit and update: These are for setting up the edit view with the checkboxes, so that you can delete specific observations. Notice that after update deletes the appropriate observations, it creates a “flash” message that summarizes how many observations were deleted. Notice that the title of this page has the name for the observation set, so you will need to establish the proper @observation_set as well as @observations. It is possible to implement this so that the view works off of @observation_set only, but I think it will be easier if populate instance variables for both @observation_set and @observations.

Views:

edit.html.erb - There should be a table around the form; checkboxes are on each row. (Big) HINT: The easiest way to make this work is for the form to be on the observation_set, and to use the checkbox_tag: check_box_tag “observation_ids[]“, “#{obs.id}” %>

new.html.erb - Standard.

show.html.erb - The interesting part is defining the form to create an observation. It will look like this:


<% form_for :observation, :url => { :action => :create_observation } do |form| %>

Now, read closely: An observation is for a particular observation_set, right? Therefore, this form must have in it a field that designates the observation_set for which this observation is destined. We are accustomed to putting all of the new data for a model into form fields — but do we want the user to be able to edit the observation_set_id? I don’t think so. Therefore, the way to implement this is with a hidden field. Inside that form you are going to need to define:


<%= form.hidden_field :observation_set_id %>

Otherwise, how would the observation_set_id get back into the params hash so that the new @observation is set up correctly . . . ?

That’s all we have to say for show.html.erb. Try and get as much of it working as you can; if you have issues, post them to the discussion board.

QUESTIONS AND ANSWERS

Q1. Can I replace the stylesheet or change the HTML?

A1. No.

Q2: Can I add additional information that is “latent” in the model? I.e., can I change what is shown in the tables?

A2: No.

Q3: Is there any extra credit?

A3: Yes. We will give a SMALL number of points (2 or 3) for an implementation of the “compare” function. Compare is a multi-stage process. First a list of links should be displayed where the user picks an observation set (you could also implement this on the index view for observation_sets), so that the user can pick which observation set needs a comparison. That should take the user to a page that would show a list of observation sets owned by other users of the same measurement kind. The UI could present a list of links or a drop-down. Once the other observation set is picked, you should show a view that compares the data. My advice is to KEEP IT SIMPLE. For example, simplying show the first and last observations for each observation set, along with the dates for those observations, would be fine. The learning process here is in the addition of controllers and views to facilitate the comparison. If you want to go nuts, you could try to rollup the data in similar fashion, and then create a Google Chart that charts both data sets — to do this will require a lot of scrounging around to figure out Google Charts. I think this would be a waste of time at this point, but I mention it for the ambitious.



Viewing 183 Comments

    • ^
    • v
    Did anyone implement the compare function for the extra credit?
    • ^
    • v
    Am I the only person that is having huge problems submitting my final zip file via gmail? It seems to be flagging all ruby code as executables and I definitely don't have any exe files in there. I already contacted Harlan to let him know I was having problems but just wanted to see if anyone had similar issues.
    • ^
    • v
    Do you have the PKZIPC.exe file in your bin/ directory?

    In several posts since the beginning of the course, I have said: Remove that file.
    • ^
    • v
    No, I removed that. Over the past two weeks when I have been sending just the contents of the "controllers" directory back and forth from home/work it wouldn't allow me to send it via zip either. I had to use ".7z" to get it to go. I assume it must be flagging ".rb" files as executable because I have literally tried deleting everything. It definitely wasn't a problem with the last assignment though which is why I am even more confused.
    • ^
    • v
    Okay, I actually tried zipping using a different program here on my work machine and it seems to have gone through. Of course I thought that last night when I sent it and it bounced back....
    • ^
    • v
    What program were you using the first time that caused the problem?
    • ^
    • v
    Hi,
    I thought I was done.. Logged back in to do a final wrap up, and now I'm confused. Do we need to submit migrations? The Paragraph at the top regarding logging in from a cookie, redirecting to measurements page, makes it sound like we might need to change our migrations. I did them for Milestone 1 but haven't touched them and have been using the provided migrations from this site.

    Am i right? Were we supposed to do a version 3 of the migrations?
    Thank you.
    • ^
    • v
    We just want to make sure that your migrations will work -- in all likelihood we won't run them, but sometimes people submit applications that have big problems so it is good to have to the code to reproduce the database.

    There are no required changes to the migrations as long as you use the ones we handed out after Milestone 1.

    Regarding using the cookie to login and to to the last observation set: That is all handled by the filter in the application.rb we originally handed out.

    The only thing you have to do his this: "When an observation set is displayed or edited, the current observation set id is copied to the current user’s attribute current_observation_set_id. You must do this as well. This allows the filter on the application controller to bring the user back to the last observation set edited, for easy addition of new data." See above. This has always been in the requirements.
    • ^
    • v
    Sounds good, thank you. I couldn't find the "redirect" code, thought it should have been in users_controller.rb, so i re-implemented it there. I'll put it in my readme. Just got off an airplane, too tired to keep searching!
    • ^
    • v
    Hi, I've got a couple questions about the tests. How comprehensive are the tests in test/unit? Are we expected or required to add tests to test/functional? And finally, is there an automagic test script for this assignment? I tried rake test and it says everything is great! Granted half the files it ran were just asserting truth.
    • ^
    • v
    I revised the tests for the code handed out after Milestone I -- you don't have to do anything extra. They are *NOT* comprehensive. Your submission will be checked by hand. OK?
    • ^
    • v
    John,
    After I run
    rake db:migrate VERSION=02
    rake db:migrate
    and I received the following error message. I am not sure why? What do I need to do?
    ActiveRecord::RecordNotFound in WelcomeController#welcome
    Couldn't find User with ID=7
    RAILS_ROOT: C:/Ruzh/Harvard/CSCI E-168/Assignment3

    Application Trace | Framework Trace | Full Trace
    C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1383:in `find_one'
    C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1366:in `find_from_ids'
    C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:541:in `find'
    app/controllers/application.rb:31:in `authorize'
    • ^
    • v
    Its working now, nevermind =)
    • ^
    • v
    I have everything working, except i cant figure why my rollups arent displaying anything, except blank rows. Is there something i should be looking at that im missing? I noticed i keep getting one day ahead in the from -to date range on the rollup page, however , even by changing this or the interval i keep getting : "There's no data for that rollup" or timestamped rows with empty rows.
    • ^
    • v
    WebMaster WebMaster , where are you?

    http://metricsmine.plugh.org/observation_sets

    We're sorry, but something went wrong.
    We've been notified about this issue and we'll take a look at it shortly.
    • ^
    • v
    As of 7:38 PM EST - no problems from my computer. Try clearing your cookies for the metricsmine.plugh.org host.
    • ^
    • v
    Apparently, 'admin' cannot view Observation Sets . I can see it now.
    • ^
    • v
    can u guys bring the test app back up, it seems to have beed down for the last hour . . .
    • ^
    • v
    It has never been down. It has failed to render a page because people keep deleting the observation kinds! Sheesh!!
    • ^
    • v
    I just wanted to confirm that you can't change the unit of a measurement, even if you create a new unit and associate it with the same measurement. Is this true? Should we enable to user to select a different unit of measurement, or are we stuck with the first, "preferred" unit? For example in the reference application I created a new unit "corpses" to be used for a certain kind of measurement of "bodies" and created a new "bugs_measured_in_corpses" observation kind, but could only, in truth, measure it in "units" -- the first unit created with "bodies" as the measurement type.
    • ^
    • v
    At present, once a unit is created, you can only change its name.

    Also, when an observation is created, the unit should be the same as the preferred unit as the observation set for which it is created. This is specified in the assignment: "An Observation has a Unit. In the initial implementation, all Observations in a particular Observation Set use the Observation Set’s preferred unit. (E.g., if the Observation Set’s preferred unit is Pound, then all Observations are also in Pounds.)" (http://e168f08.plugh.org/assignments/assignment...).

    Eventually, it would be nice if one observation could be recorded in pounds, and then later in kilograms, with automatic conversions between units of the same measurement kind.

    Also, at present, when you create an observation set, you never pick the unit. You only pick the KIND, and, by specification, "also set the @observation_set’s preferred unit to the first unit of the selected ObservationKind’s Measurement!!" (http://e168f08.plugh.org/assignments/assignment...). Notice that we have not defined here what "first" really means; as long as you set the observation_set's unit to SOME unit that has been associated with the measurement of the picked observation kind, you'll satisfy the requirement. I probably should have said "first in order of create time." In any case, lacking an ability to convert between units of the same measurement, it makes no sense to allow a lot of flexibility with units.
    • ^
    • v
    Hello!

    My tests complained that a new ObservationKind was created without a :measurement_id value. My ObservationKind model file includes "validates_presence_of :measurement_id".

    First, it looks like the validation isn't working. Wha?

    Second, I started a new migration, adding ":null => false" as an option to change_column:
    change_column :observation_kinds, :measurement_id, :null => false

    but the migration failed with the message, -- change_column(:observation_kinds, :measurement_id, {:null=>false})
    rake aborted!
    undefined method `to_sym' for {:null=>false}:Hash

    WHA???
    this seems nuts! any suggestions? thanks.
    • ^
    • v
    You shouldn't need to change any associations or validations on the models, so I would recommend removing validates_presence_of :measurement_id - if you do leave it in, it is critical that your code run with the original migrations; if the original migrations (or automated tests) don't work, remove it for sure.

    The reason your call to change_column is failing is because you left out the type: See the doc;

    change_column(table_name, column_name, type, options = {})

    http://api.rubyonrails.org/classes/ActiveRecord...
    • ^
    • v
    thanks.
    • ^
    • v
    FYI It looks like the reference implementation generates a server 500 internal error if you try to view a rollup for an observation set with no observations.
    • ^
    • v
    I fixed it in the reference implementation (reset the db, too). It will take a bit more work to fix that on http://www.metricsmine.com so I will leave that server alone for now.

    Thanks!
    • ^
    • v
    Good catch -- I will fix that. That doesn't affect anything you need to do for submission.
    • ^
    • v
    I can't seem to grab the variables submitted by the "datetime_select" helper. The dynamically created HTML in the overall form looks correct:
    <form action="/observation_sets/create_observation" method="post">
    <input class="text large" id="observation_notes" name="observation[notes]" size="30" type="text" />
    <select id="observation_date_1i" name="observation[date(1i)]">
    ... and all the other (2i), (3i)... fields
    </form>

    I can grab the "observation[notes]" field (shown above) just fine, but for some reason just keep getting nil values when trying to work with the "observation[date(1i)]" fields.

    params[:observation][:notes]
    grabs the notes, but
    params[:observation][:date]
    won't grab any dates... and
    params[:observation][:date(3i)]
    throws an error.

    Played around with
    convert_date
    to no avail.

    This has got to be simpler than I am making it. Probably a one-liner...?
    • ^
    • v
    Rails rolls up the data in these multi-part fields for you -- you can access it using params[:observation][:date], and send it to the db like that.
    • ^
    • v
    I tried that
    params[:observation][:observed_at]
    as well as
    Observation.new(params[:observation][:observed_at])
    (ie. the "date" field is renamed in this application to "observed_at")
    and it just does not work.

    I just keep gettting an error
    "Couldn't find rollup for observation at "
    The date is not being received at all.

    In the error message there is a "Request Parameters" section that shows clearly that the parameters are getting sent across correctly as follows:
    {"observation"=>{"observation_set_id"=>"2",
    "observed_at(4i)"=>"04",
    "observed_at(5i)"=>"31",
    "observed_at(6i)"=>"45",
    "notes"=>"abc",
    "amount"=>"123",
    "observed_at(1i)"=>"2008",
    "observed_at(2i)"=>"12",
    "observed_at(3i)"=>"7"},
    "commit"=>"Add"}

    I think there may be something wrong with my system's helpers when they are catching and reconstituting the date fragments.

    I will send my code to Keith right now.
    • ^
    • v
    Observation.new() should create a new Observation object, right? So the params hash that you pass to new() should be a set of attributes of that object, i.e. in this case, attributes of the Observation class. params[:observation] is an appropriate such hash, but params[:observation][:observed_at] is just the parameters for the observed_at field, You might be able to get away with something like

    observation = Observation.new()
    observation.observed_at = Time.new(params[:observation][:observed_at])

    but why go to the trouble of addressing this level of detail when creating your observation?
    You have everything you need in params[:observation] -- the observation_set_id, notes, amount, and all of the pieces of observed_at.
    Just invoke Observation.new(params[:observation]), and trust Rails to unpack everything properly for you.
    • ^
    • v
    My point, as I noted below, is that you cannot access params[:observation][:observed_at]. Rails is smart, but not that smart -- those parameters are unpacked by ActiveRecord. There is no key :observed_at in the params hash in the controller -- dump the hash in the console and try accessing it! It will give you a nil. You're right in that you don't want to mess with these multi-part data types in the controller, but what I originally said was incorrect about how to access it if so inclined.

    As I said, generally, you want to build your forms so you can do as you described, and mess with parameters only on rare occasions.
    • ^
    • v
    Right.

    Naturally, I've been watching this discussion of datetime_select with some interest.

    My main comment for students struggling with datetime_select is to look at example code:

    In the ChildCare Co-Op app, app/views/playdates/list.html.erb . . . and app/controllers/playdates_controller.rb (see the "create" action).

    As you see there, datetime_select does all of the heavy leifting -- you don't have to dig into the key of the instance object, nor its pieces.

    The one additional piece here is that there is an option :include_seconds which is documented for other tags; despite its omission from the docs for datetime_select, it does exist. I sent around an e-mail on this topic awhile back.
    • ^
    • v
    You shouldn't even need to access params[:observation][:date]. If you name the field appropriately in the call to datetime_select, so that it's the name of a column in the observations table, then you can just call Observation.new(params[:observation]), and by the magic of Rails, everything gets unpacked just right.

    But: to figure out what's happening with parameters, in general, I've found it very useful, when I get totally confused, to stick the line

    puts params.inspect

    into a controller action, and then go look at the output from my server, to see exactly what it is that the controller is seeing after the user posts the form.
    • ^
    • v
    Morris is more correct than he realizes. It is ActiveRecord that correctly interprets your multi-part data; if you try to access the params hash in the controller using the key I specified above, you'll get a nil value. At that point it is still just a hash. Once you pass the parameters to Observation.new, then AR will handle the input correctly.

    In general you want to construct your forms so you rarely, if ever, need to futz with the parameters, especially in basic CRUD actions.

    I'm getting a lot of questions from people having trouble with params. Outputting it with params.inspect, tailing your development log, whatever -- it is important to know what is being passed to your action, and what the structure of the hash looks like, in order to debug effectively.
    • ^
    • v
    I don't think you need to access the fields individually unless you want to modify them before insertion. According to John you shouldn't modify the date fields at all as they are in UTC format and should be inserted/updated as UTC in the database. When I do my new I pass the entire object and it synchs up all of the fields from the form when it does the insert. I'm checking to see if I have to do any form field editing, so this may change, but I hope that I can have that all done prior to the create_observation new is invoked. Actually, I think the database validations should catch all these if they're defined correctly. Take a look at the invitations_controller in the CCC app to see what I'm talking about with regards to passing the entire object to the new.
    • ^
    • v
    Right, you shouldn't have to do anything.

    Incidentally, at work we have noticed that there are problems with datetime_select on Rails 2.2.2, so I hope you haven't inadvertently updated your Rails version!

    If you continue to have problems, post.
    • ^
    • v
    I'm having a problem with one of my "field too long" checks which is kind of odd. I have my validates_length_of set correctly and an error_messages_for and error_message_on my observation_kind new.html.erb form and I get a nil object error when the name value is 31+ in length. I'm doing exactly what I do for other forms and it works fine elsewhere. Does anything pop out in anyone's mind why this might occur? It's sort of look's like an array out of bound situation (I'm guessing). The strange thing is that the stack trace shows that it's in the collection_select for the measurement names. I'll keep looking for what i've done wrong here.

    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_view/helpers/form_options_helper.rb:214:in `options_from_collection_for_select'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_view/helpers/form_options_helper.rb:398:in `to_collection_select_tag'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_view/helpers/form_options_helper.rb:133:in `collection_select'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.1/lib/action_view/helpers/form_options_helper.rb:445:in `collection_select'
    app/views/observation_kinds/new.html.erb:11:in `_run_erb_47app47views47observation_kinds47new46html46erb'
    app/views/observation_kinds/new.html.erb:5:in `_run_erb_47app47views47observation_kinds47new46html46erb'
    app/controllers/observation_kinds_controller.rb:33:in `create'
    • ^
    • v
    It is hard to tell w/o seeing the view and controller code. Can you email your TA?
    • ^
    • v
    I'll send it right over to you.
    • ^
    • v
    <%= check_box_tag (:observation_ids[], "#{obs.id}") %>

    How does this line work? :observation_ids[] isn't something I have seen in my code. Is this meant to gather the observation.id into an array? I gather that the obs.id will send the obs.id to the update method so that an observation can be deleted.
    • ^
    • v
    I discussed it at some length in one of the lectures, and said things like "you will need to understand this for Assignment 3."

    The checkbox technique is also used in ChildCare Co-Op. Please review those materials.
    • ^
    • v
    I do have it implemented and working (not exactly as written above of course). I will do some more research to make sure I understand how its working. In the end, its probably my update method that isn't handling the information correctly.

    Thanks!
    • ^
    • v
    Cool.

    The short answer is that when you put [] after an attribute name, Rails will magically take each check and assign "true" to the array element for the check id.

    It's totally non-obvious, which is why I discussed it in lecture, and recommended that people look at the ChildCare Co-Op code.
    • ^
    • v
    If there is a time difference between the default time on one of the MetricsMine.Plugh.Org "add new" forms and my own, then should I synch my copy to that?
    • ^
    • v
    No.

    One thing you want to watch for is this:

    -- If in your own implementation you add an observation at 5:00 PM, it should show up as 5:00 PM in the list.

    What is going on here is that times are stored in the database in UTC (universal time). If you made the mistake of entering dates in, say, local time, you could get a discrepancy.

    it is unlikely that this is happening to you.
    • ^
    • v
    Unit/Kind of Metric Edit functionality. The page is functional, but there is a warning in the app that says - We know you'd like to change the measurement, but since these are shared, the measurement needs to stay the same.) Should we implement the same behavior in our application
    • ^
    • v
    Please do!
    • ^
    • v
    observation_kind and unit have the same relationship to measurements right?

    For an observation kind I can say something like observation_kind.measurement.name because all the methods are made available to the observation_kind through the measurement relationship.

    Should I also be able to use the same relationship with units? For example unit.measurement.name? When I do this from the unit's index view the measurement is nil.
    • ^
    • v
    Could you double-check that from the console for a unit that we created in the original migrations? E.g.,

    ruby script/console
    Unit.find(:all).first.measurement.name
    • ^
    • v
    I got a result in the console. I wonder what I've done to break the relationship in my controller so that the this code doesn't execute in the view.
    • ^
    • v
    For all units? It may be that you added a unit with a null for the measurement . . . i.e., a bug in your code?

    You should be able to do:

    Unit.find(:all).each { |u| puts u.measurement.name }

    I.e., iterate through all of your units, and see if any break on the following of the measurement association.
    • ^
    • v
    I ran migrations back and its working better.
    • ^
    • v
    Good - you should review your code carefully, though, 'cos it sounds like you got some bad data in there.
    • ^
    • v
    Can you comment on what we need to package and submit to our TA for assignment III? Thanks.
    • ^
    • v
    I have a longer page coming regarding grading, etc., and I am waiting for the TA's to finish reviewing it.

    The submission is like so:

    0. Before submitting, verify that the migrations work! I.e., delete (or rename) db/development.sqlite3 and do "rake db:migrate". Check out your app! It can happen that you are relying on bad data being in the database, so exercise your app with a clean slate.

    1. There should be a small readme text file in the root of the project with your name, e-mail address, and the name of the project -- this is simply so that if we change the name of your project we can still figure out whose it is!

    2. If you are doing anything "unusual" or have bugs that require special discussion, include that discussion in the readme. There is NOT a requirement for a "writeup" for this assignment, because the assignment is essentially about fulfilling a fairly narrow set of requirements. Do include judicious code comments for anything that is unusual, weird, especially superb, etc.

    3. You may have a file bin/PKZIPC.exe - remove it. Your ZIP won't go through some e-mail agents with it included.

    4. ZIP your project with

    rake package

    It is possible that this will fail on systems that do not have a working ZIP program -- we have a ZIP in Ruby included, but it can sometimes break on Windows.

    If rake package doesn't work, ZIP up your project with any ZIP program. If you have to manually ZIP, remove the files from tmp/ and log/ . INCLUDE YOUR NAME in the name of the ZIP archive.

    E-mail it to your TA.
    • ^
    • v
    So we should ignore the "e168:submit" task shown by rake -T, described as " E168: Create ZIP for submission"?

    Also, you say we should delete our database and rake db:migrate. Do you want us to package our submission with our test data in the database, or just a clean database, or none at all? Or does this even matter?
    • ^
    • v
    Let me get back to you on e168:submit - I need to take a 2nd look at the rake script.

    The safest thing would be to rename your "good" database. So that way if it turns out that your migrations fail, we can still do some forensics to figure out what's going on.

    I need to double-check the Rakefile 'cos it may do something funny with db/

    John
    • ^
    • v
    Not sure if this was resolved or not, but... I noticed that in the reference implementation that the date on the observation_set SHOW page is not the actual date and time. Is this intentional? I did see mention at the end of this blog about adding some Timezone support for the final project, but didn't want to jump into that at the moment. In the interim I've added something that displays the correct local date & time to the datetime_select. I just wanted to check if there was a reason why the reference implementation displays the date & time the way it does and if it's ok for mine to be different.
    • ^
    • v
    The times are in UTC (like Greenwich Mean Time [GMT]). All data is stored in the database in this format. For the final project, you could choose to DISPLAY such data in the time zone for a specific locale.

    But, generally, you want to store time/date data in UTC.
    • ^
    • v
    Oh, I understand now. Thanks. I used DateTime.now as the default on the datetime_select and would have to convert any dates that I store in the DB back to UTC format. Probably not worth the effort and best accomplished using Timezone support. Thanks for the quick reply.
    • ^
    • v
    You shouldn't need to use DateTime.now at all! See what happens if you don't "pre-fill" that field.

    Also: It is easy to create UTC times . . . you might have noticed in models/rollup.rb, db/migrate/data_add_rollups.rb and elsewhere.

    In other words: If you stick to UTC, you don't have to do any conversions.
    • ^
    • v
    I've removed it and the datetime is back in UTC time. Now that you've explained it to me it makes perfect sense.
    • ^
    • v
    I trying to test validation on observation_sets/create_observation and I left blank amount and notes. I received the following error:
    Couldn't find rollup for observation at
    Application Trace | Framework Trace | Full Trace
    app/models/observation.rb:36:in `before_validation'
    app/controllers/observation_sets_controller.rb:53:in `create_observation'

    I could not figure out why? Could you guide me?
    • ^
    • v
    Before an observation is validate, a row from the rollups table is looked up based on the "observed_at" value for the observation.

    If "observed_at" is bad, then no row will be found, and that code will fail.

    Therefore, double-check that you are setting observed_at is being set properly.

    There are only rollups for dates between 2008 and 2010 -- so there could be an issue if you add an observation farther in the future. If you look at the rollups migration, you should be able to figure out how to create more rollup data for more years in the future.
    • ^
    • v
    I notice that Metrics Mine, as specified and as implemented in the reference implementation, doesn't use the user_id of an observation_set, except for choosing which observation sets to display on the observation_sets/index page. By editing URLs, I can easily view and edit the metrics of other users. Is it correct that for this assignment, we shouldn't be worrying about this? I thought of this because I was looking back at Milestone 2, and trying to figure out where I would have used finds numbers 4 and 5, which say, "Ensure that the observation_set is owned by a particular user."
    • ^
    • v
    You can skip that requirement -- I forgot to implement it in the reference implementation! I'll note that in the next lecture.

    For the final project: A great thing to do is to try to manage URLs so that they aren't sequential numbers. Even if you check the user who supposedly owns a given resource/item, it can be good to not even reveal the fact that something exists at a certain id. To do this, you would add a column and you would set it to some String version of a Hash of unique info for that record; then look up by that added id, rather than by the primary key.
    • ^
    • v
    This may be a really obtuse question, but i'm stuck on the very basics. I think i've made the app\views\observation_sets\new.html.erb file properly, and also filled in the underlying observation_set controller (Even added a dummy function called "create" to the helper object), but as far as I can tell, none of those code blocks run.

    Is there a way to print debug info out to the console or something? I want to see some errors at least, or find out where my mistake is.
    • ^
    • v
    Well, the console already logs the name of the controller that is picked as well as the contents of the params hash.

    You say that you created a CREATE "function" (I assume you mean method?) in a helper object. Action methods should be on the CONTROLLER, not on any helper objects.

    So, the upshot is:

    (1) In the observation_set.rb file, which defines ObservationSetController, you should define a "create" method. This is the method that allows you to create a set of observations. It will look something like this:

    def create
    # you add your code here
    end

    (2) When a specific observation is added, that is handled by a method called create_observation. So in that same file you will need:

    def create_observation
    # you add your code here
    end

    In both of these methods, you may find it helpful to add calls to the "puts" method to dump whatever debug code you want to the console.

    One last thing: Everything I've said here I said in the assignment description above in the section that starts: "Controller: ObservationSetsController
    Notice that this controller manages updates of BOTH ObservationSet and Observation. This is not an unusual pattern. Since Observation is almost completely a “slave” of ObservationSet, it is convenient to manage both Models in the same controller. When we get to REST, we will talk about changing this."

    And then I went on to define exactly the methods you need to define. I am not sure what you mean in your post about writing a "dummy function" (there are no functions per se in Ruby) or "the helper object" (since you really shouldn't need to do anything with helpers).
    • ^
    • v
    Thank you, I'm on the right track now. It is so hard to drop the C/C++ conventions when using that stuff every day! Thanks.
    • ^
    • v
    I am getting the following error when submitting "Create" forms:
    "You have a nil object when you didn't expect it!
    The error occurred while evaluating nil.has_key?"

    I have gone through the book many times, through your Lecture 9 slides, reviewed the "CRUD" application code (which all runs just fine on my machine).

    To try and fix this issue, I am working with the admin's Measurements "New Measurement" form, which is the simplest.

    The HTML produced on my form is identical to that on metricsmine.plugh.org. So there must be a problem on the "measurement.rb" or "measurements_controller.rb".

    The error is being thrown by the following line in the "def Create":
    @measurement = Measurement.new(params[:measurement])
    If I remove the code that does the create / insert, and just pass the #{params[:measurement]} to the "flash" message on the index page, then the results of that printed variable are:
    nameasd
    (where I typed "asd" into the name field).

    For the above I had not initialized any variables in the "def new" with any variables. If I add
    def new
    @measurement = Measurement.new
    end
    to the controller, then I can't even get to the "New Measurement" form at all. Clicking on the "New Measurement" link gives me the error:
    wrong number of arguments (0 for 1)

    Otherwise, I am progressing, but I've been picking at this one crucial issue for too long now. Please assist. Thank you.
    • ^
    • v
    Three things:

    (1) In views/measurements/new.html.erb: What does your "form_for" line look like?

    (2)

    Double-check that your Measurement model, defined in measurement.rb, looks like this (this is what we handed out with the "solution" for the associations and validations milestone):

    class Measurement < ActiveRecord::Base
    has_many :units # 7b
    has_many :observation_kinds # 6b
    validates_presence_of :name
    validates_uniqueness_of :name
    validates_length_of :name, :maximum => 30
    end

    (3) Remove your file db/development.sqlite3 and re-run your migrations from scratch. Important: you should be using the model definitions (with its associations and validations) and migrations from the solution download.
    • ^
    • v
    1) I assumed that my "form_for" was good, given that it is returning the exact same HTML as the Plugh site.

    2) HOWEVER, I found the following in my measurement.rb. Once I removed it, then everything worked fine.
    def initialize(measurement)
    @measurement = measurement
    @name = name
    end
    I must have added this when in my "I'll try anything" stage.

    3)...

    Thank you!
    • ^
    • v
    Whew -- so what that was doing was setting @name to nil. And thus your error message from before.
    • ^
    • v
    Can you provide me some guidance on how to dynamically change the background color of the newly added row on the create_observation page. I'm struggling what to use to help determine if the row should be highlighted. Thanks.
    • ^
    • v
    Well, here's what we say above (and I'll add some annotations in square brackets):

    In the reference implementation, the id of the newly-created observation is put into the flash [did you do this?], so that when the list of observations is re-displayed, we can change the background color of the row [Have you figured out how to do this?]. You need to do this, too; to get it to happen you will want to dynamically change the style element on the correct <tr> tag [do you have a way to determine the correct <tr> tag?]. E.g., it would look like:

    <tr>

    when the row shouldn’t be emphasized; and

    <tr style=”background-color: #E0FFFF”>

    when it should be emphasized. This is the sort of thing you can glean from view/source for the reference implementation.

    ---------------------

    So this means that when you display the <tr> element for the row, you are going to have some code more or less like this:

    <tr <%= if SOMETHING then '' else 'style="background-color: #E0FFFF"' end %>>

    The part after the "then" is when the condition holds -- i.e., when it's an ordinary row; the part after the "else" is for when the condition doesn't hold, which would be the case when you want to "decorate" the row. There are other ways to get the effect: You could create an actual style and then select it with the "class" attribute on the tr element.

    The "EOFFFF" is from inspecting the rendered HTML of the the reference implementation (after adding an observation).

    You have to figure out SOMETHING. It is an expression based on the whatever you put in the flash that indicates the item number of the most-recently-added observation.
    • ^
    • v
    Thinking about this, I realize that if you're putting something in the flash, you must be REDIRECTING to show, in the reference implementation. In my implementation, the last thing create_observation does is to RENDER show. This allows me to bypass the flash, and just make sure that my newly-created observation is an instance variable, which I need to do anyway, to be able to display error messages for the create-observation form. This seems easier to me -- is there any particular advantage to getting back to show via a redirect? As far as I can see, the user can't tell the difference, because the resulting URL is the same.
    • ^
    • v
    In your impl, what happens if you re-load the page (control-R) after you've rendered rather than redirected?
    • ^
    • v
    Yes, I realized the problem after posting, while eating supper. If you're modifying your database based on the URL or on POST form data, you must redirect to display the results, to keep a refresh from repeating the action. I got distracted from this basic point because in some cases we're re-rendering the page with errors, without redirecting but also without modifying the database.
    • ^
    • v
    So, the idea is this:

    -- If there are errors, render. Why? Because you use the instance variables to trigger to the error display.
    -- If there are no errors, then you want to redirect so that the user gets a fresh page and a page reload won't re-submit the form.

    Other frameworks will redirect for error display, too; the reason Rails doesn't is presumably because it means using the session too much.
    • ^
    • v
    In the reference implementation, I don't see me being directed to a page to "add observation".
    We are supposed to save the observation set id into the user table. We save off the last observation set the user chooses.
    However, I don't see how we use this information.

    When I log on, I get to the dashboard, which allows me to:
    - logout
    - Get a list of metrics (i.e. observation sets)
    - Create a new observation set
    - Compare

    So, I don't see how and where we direct a user to a page with the most recently used observation set.

    The assignment reads:
    "There are some small changes between this version and the prior version: 20081111021247_add_current_observation_set_id_to_user.rb adds a column to user “current_observation_set_id” - whenever you view an observation set, the id is saved here so that when you log in from a cookie, you can be redirected to that set: This makes it especially easy to enter a new observation for whatever set you were last looking at. "

    So, when I log on, assuming that there's a cookie, do we not go to the dashboard, and instead go straight to the page where we can add new observation s?

    Thanks
    • ^
    • v
    To see how you get directed to the page on which you would add an observation:

    (1) Log in.
    (2) close your browser without logging out.
    (3) Go back to the application. See where you end up?

    If this doesn't work for you, let us know.

    Reason for this behavior: There is ONE activity that the user wants to do every day: Post data. If you have ever tracked your weight, you will do anything to avoid this behavior. Therefore, the application makes it as easy as possible.
    • ^
    • v
    This doesn't work. I am using FF 3.0
    It takes me to the dashboard.

    BTW, why do you need o save the information in the database as well as in the cookie ?
    I thought that if you save it in the database, then once you look on, you will get the observation set information from the database.
    If you save it in the cookie, then you get it from the cookie. Why do we need both ?

    Thanks
    • ^
    • v
    What is the username that you are using with http://metricsmine.plugh.org that doesn't work in FF 3.0?

    When you say: "why do you need o save the information in the database as well as in the cookie ?", what do you mean by "the information"?
    • ^
    • v
    I was trying to delete all the metrics I created as an admin on the reference implementation.
    It delete multiples rows for each delete key I hit.
    I hope that you can reproduce this. Perhaps my problem with ObservationKind delete is related or similar.
    • ^
    • v
    I don't understand what you're saying, because you're not using the language of the application.

    If you are deleting observations (metrics), you would use the checkbox and then click "delete checked." There is only one button here, so I don't know what you mean by "each delete key I hit."

    If you are deleting observation kinds -- "kinds of metrics" in the UI -- you would be clicking the delete link.

    Note that when an observation kind is deleted, then the display of the KIND at the top of the "show" page for the observation set can no longer display the kind. So it is blank. There is an instruction regarding this in the static page for the "show" template.
    • ^
    • v
    I logged in as Jenny
    Also, "the information" is the observation_set id.
    I thought we're supposed to save off the last used observation_set id somewhere, so that when the user log on again, he gets send to the page whereby he can add a new observation for the observation set he last used.



    Now as an admin
    I also noticed that in the reference implementation, the delete also seem to have rows (observationKinds) automatically disappearing.
    Also, when I hit destroy for some of the ObservationKind, I to an error page.
    • ^
    • v
    That is correct: When you display a particular observation set, save the current observation_set_id to user.current_observation_set_id.

    I cannot reproduce the "automatic" disappearance of observation kinds, or any error page. If you delete all of the observation kinds (PLEASE DON'T!) you will find that you can't create a new observation set (I think). This was discussed earlier, and we said: "An admin would never delete all of the observation kinds, so we will consider this a feature, not a bug."

    I have just reset the database. If you can identify a set of seps that will produce this behavior, from login to the error, e-mail the steps to me.
    • ^
    • v
    I think I know the answer to this, but before I get around to trying it out:

    This will require me to modify my browser settings to accept persistent cookies, won't it?

    (But shouldn't it work equally well to leave the browser open and simply close the tab or window that's connected to the metrics mine, and then go back to the application?)
    • ^
    • v
    You may be able to set an exception to allow a persistent cookie from one site (e.g., metricsmine.plugh.org); or, perhaps better, localhost.

    I am not 100% about this, but I think if you close all tabs to a site, and then re-open a tab, your prior session cookie will still be used (which makes sense from many typical end-user cases -- if you accidentally close a tab, you don't want to have to re-log in).

    Also, it is worth nothing that Internet Explorer and Firefox work differently with temporary cookies (not your question, but related). You can block a temp cookie on IE, but not, to my knowledge, on FF (though doubtless there is a browser plugin for FF that will do it). Also, if you're a security zealot, IE implements P3P, which is pretty great, though few sites implement it server side (one that does is my old company, h3.com - https://www.h3.com).
    • ^
    • v
    OK, a question about the user-interface design of this:

    Why would we want to limit this convenience feature to people auto-logging-in with a persistent cookie? Isn't the redirection to the current observation set equally (or more) useful to someone who logs in daily from their public library or school's lab, or someone travelling around the world tracking their latitude in Internet cafes? The way I use my own computer, taking me from the home page to the desired observation set is of almost no use at all, first because my browser discards persistent cookies on exit for privacy reasons, and second because for sites that I visit frequently, my bookmarks generally take me not to the home page of a site, but directly to the page I'm interested in (and if those pages require login, most well-designed sites will redirect me to a login page and then from the login send me directly to the page I was trying to get to).
    • ^
    • v
    That sounds reasonable. The way it is implemented this way is because the notion is that you want to log in + go to your "home" in an environment where you are most "at home" (where you dropped a persistent cookie).

    If you logged in at school on a computer where you didn't have a cookie, do you want someone looking over your shoulder to know right away that you've blown your diet?

    It is definitely the kind of thing that would get tuned based on user response.
    • ^
    • v
    In the reference implemenation, if you click the "Delete Checked" button,
    and if you do not check any box (for observations), then, there will be a page telling me that something went wrong.
    • ^
    • v
    Looks like that is a bug.