Assignment: Final Project Proposal and the Final Project
This is now final, though the list of “features” (item 8) will grow a bit. Stay tuned.
The Final Project (hereafter, FP) will be a web application designed and implemented by you. The basic idea is that you come up with a project of similar complexity to Assignments 4 and 5, with some additional features.
Proposal due date: Nov. 19. Proposals submitted earlier will be reviewed and approved earlier.
Final project due date: Dec. 17. Note: This due date is absolutely final, owing to Extension rules regarding examinations and final projects.
The requirements are as follows:
- You must write a FP Proposal and have it approved by your TA. (Approval means that you have an e-mail from the TA in which the TA writes: “I approve.” Your TA may tell you that the project is approved only if you make some changes in the proposal; if so, make the changes, and get that final approval!)The FP proposal talks briefly about what the application will do, what its models, controllers, and views are like, and what additional “features” you will implement — more on features below.
- Due date for the FP proposal: The due date for the final project proposal is: Nov. 19. If you can get your proposal in sooner, the staff will make every effort to provide feedback sooner rather than later. One thing you might consider is to give your TA a brief “pre-proposal” that provides in a paragraph some idea of what you intend to do before you write the full proposal; by this means, you might be able to get a bit of early tuning.
- The FP proposal must be a document written in plain English (i.e., not just an e-mail, and not a PowerPoint or KeyNote slide deck; it must be a PDF, an RTF file, a TXT document, or a ZIP of an HTML page). The audience of the FP proposal is an informed developer who needs to know the application’s scope and (high-level) how it will work. You should include enough information so that the developer would be able to evaluate whether or not he or she would want to implement the project. It is not a specification; it is a proposal. Please, do not provide a cover page, table of contents, list of figures, etc., etc.: Stick to plain sentences and paragraphs; lists can be useful for things like your descriptions of models and use cases (see below). How long should it be? My advice is to keep it as short (but clear) as you can; your TA will be able to tell you quickly if there is not enough detail, and then you will have time to resubmit.
- The FP should accomplish something. It should allow a user (or users) to get something non-trivial done. You should begin your FP proposal with a description of what the application accomplishes, and why you think anyone would be interested in it. Your FP proposal should “argue” a bit for the usefulness of the FP. If you like, include real-world data on who would benefit from the application, perhaps in terms of getting its task done cheaper, faster, or better. In the past, some of the best final projects have been: (a) a tool to help the developer with a hobby or other topic about which the developer is passionate; (b) a clone of part of an existing application (if you want to clone an existing application, there should be some kind of significant twist that differentiates your project); (c) something that would be of use to a family member; (d) something that would be useful at work; (e) an application that “mashes up” two or more web-based third-party APIs (e.g., Amazon’s or eBay’s services to provide information about products). One thing we haven’t seen much of is genuinely interesting games.
- Models: Your FP must have a list of Models that is of similar complexity to Assignment 4/5; i.e., five (or so) or more database tables, and relationships amongst the models. We expect you to use at least one has_many :through or, possibly, a pair of habtm relationships (as you will recall, John prefers has_many :through and hasn’t said much about habtm ["has and belongs to many"], but you can pick it up easily from AWDR). Models must define sufficient validations for the application to work properly (e.g., there should be no surprises because, say, two users have the same login name, if your application expects users to be unique). When you describe the models in the FP proposal, you NEED NOT include a diagram; you can simply list the models, what they represent, and their attributes, associations, and validations. The list should be easy to read. You do not need to list exhaustively all of the attributes — but we do need to hear about all of attributes that are functional.
- Use cases: Your FP must implement several use cases that exercise the models for one or more types of users. In the proposal and write-up, we like a list of sentences of the form “The user will be able to X.” For examples, see the requirements for last year’s MetricsMine application (http://e168f08.plugh.org/assignments/assignment-3-2/), or for the previous year’s ChildCare Co-Op (http://e168f07.plugh.org/2007/10/21/assignments-4-5-and-6-overview/). It can also be helpful to provide a user story or scenario (again, see MM or CCC). Your TA may well ask for more or less detail on this when reviewing your proposal.It will count negatively against your grade if there are models that are not exercised by the implementations of the use cases, or are exercised trivially. In your FP proposal, you must define the user (or users) carefully, and explain which use cases apply to which users. In large part this is where your FP proposal will talk about controllers. NOTE: The use cases play a special part in the FP Write-up (see below).
- Pages: You should itemize the most important pages and explain how the user experience in the use cases flows through those pages. In large part, this is where the FP proposal will talk about actions and views.
- Two Features: In addition to implementing models, controllers, and views, you must leverage two of the following additional features of Rails or plugins (depending on feedback from you, we may add to this list):
- E-mail (counts as only half a feature, unless the application makes significant use of e-mail). Send e-mail; but, more importantly for the e-mail feature, the e-mail must be functional to the app. In other words, it might notify users of a change of state in the application, and provide links that, when clicked, change the state of the application. In other words, merely sending notifications is not enough. (And e-mail confirmations sent by restful_authentication or other plugins is not enough.) You might also consider receiving e-mail. These topics are covered in AWDR.
- User management (counts as half): Adapt the login / registration code to use the Clearance Gem (http://github.com/thoughtbot/clearance).
- Ajax: Ajaxify as much as seems appropriate. Using Ajax on one or two pages will result in very little credit. Creative, dynamic use of Ajax will be reward, as well as systematic and consistent use of Ajax throughout the application. Ajax is covered in AWDR.
- REST. Provide a REST interface for at least one of the models. Ideally, you will implement nested resources. If you expose resources through REST, you must provide a sample client. Your best bet for a client is to write a simple application using ActiveResource. . . . covered in AWDR.
- Feeds: Expose an RSS or Atom feed with updates regarding the state of some aspect of your application. To get started: http://intertwingly.net/blog/2008/10/14/Rails-AtomFeedHelper-just-got-better
- Asynchronous jobs: Manage tasks through Workling (http://playtype.net/past/2008/10/2/workling_version_03_released/) or something similar.
- Uploading. Try paperclip: http://www.thoughtbot.com/projects/paperclip/; AWDR also provides some guidance on supporting uploads in Rails.
- Time zone handling. See http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/
- Internationalization or Localization: Provide a means to present your application in another language. THis can be a big topic: Discuss with your TA if you want to try it.
- Testing: Provide a complete test suite. This may count as two features. A serious attempt at this feature would require learning about rcov, possibly mock objects, and possibly an alternative (to RUnit) test framework such as Shoulda. If you want to do this, you should already be a testing zealot.
- Something else. You must get approval from your grader.
- If you propose an application that has significant domain complexity (say, a project with 15 tables and a lot of use cases), we may accept a proposal that specifies only one of the above features.
- A few notes about the final project packaging, writeup, internal documentation, and implementation (and we will likely have more to say in this department):
- The project must have the standard Rails directory organization (i.e., the result of running the “rails” command). We can’t accept assignments that have some kind of home-grown structure. It must be possible to start the server with “script/server” and so forth. Models, controllers, views, and migrations should obey the standard conventions regarding positioning in the directory structure, naming, etc.
- The project must run in the environment you set up for Assignment 0! (So Rails 2.3.3, etc.; please, no Rails 2.3.4 or later, or edge Rails!)
- Your rakefile must be based on the course Rakefile from the last version of Assignment 4/5. What you submit should be produced by “rake package.”
- It must be possible to run all migrations.
- The Rakefile for Assignment 4/5 does include a copy of the development database (db/development.sqlite3) in the ZIP. We do want this in case there are issues with your migrations. So don’t delete it prior to packaging.
- You must include sample data, i.e., a data migration that sets up sample users, data, etc.
- If you are using a gem or plugin that interfaces with a third-party (Amazon, eBay, etc), provide clear instructions on how to set any required components (including how to authenticate, if necessary) on the TA’s system.
- The project must be accompanied by a write-up, which is a plain TXT document (called readme.txt or an HTML document (called readme.html) which goes in the root of the project. Keep the formatting as simple as possible. The only reason we allow HTML is to make it a bit easier for you to include screenshots if you so desire.
- The write-up should cover the same topics as the proposal, but with a greater focus on implementation.
- As in the proposal, the write-up should include a list of use cases, and a clear explanation of how to exercise each use case; if you want to get credit for what you have done, provide us a way to see what you have done!
- The “crow”: On occasion, we have received submissions that do something incredibly cool, but for whatever reason the student forgets to tell us about it. Do not forget to “crow” (i.e., brag) about anything that is particular cool or amazing in your project. And don’t forget to tell us how to exercise that cool feature!
- As promised at the top of this page, we will provide another page with some details about how to create a great writeup. This document will also talk some about internal documentation.
Are you discouraging us to use STI and polymorphic assocations?
I have a Person, Customer, Manufacturer thingie going on and was wondering if I should learn one of the above?
@Lateral Punk
STI works fine. I've downplayed it, because typically people find that their models are not really subclasses. E.g., in your case, do Person, Customer, and Manufacturer hold the "is a?" relationship with one another? If you find you need to add extra columns to support Manufacturer, then you start to get some drift in STI, and before long, you'll find yourself getting really angry with it.
So . . . by all means try it, but understand that you may find it very annoying after awhile.
Unable to convince script/plugin to download acts_as_list from github, I git cloned it my machine and copied the monkey patching into a file in lib. That didn't fully work: I needed to require that file into my model.
This all seems grotesquely unconventional. Is there a standard way to move a plugin into one's rails application if the code for it resides locally? I wasn't able to google myself a how-to.
@Ken Busch
Download as a ZIP, and open the archive and put it under the "vendor/plugins/" directory.
@john
Too simple, that!
@John - Yes it got annoying fast (STI) so i dropped it
What you just described to Ken, could I do the same thing for other plugins like the seed-fu?
@Lateral Punk
If the plugin works with 1.9.1. Sometimes there is more information on that here: http://isitruby19.com/
On occasion, there will be a project at github that describes itself as a plugin, but isn't really a plugin, so it might not work. But it's worth a try.
I really think that for seeding data, there is nothing THAT wrong with using a data migration.
For look-up tables and stuff I agree that data migrations are good...but for development/test user generated content e.g. sample customers, I think it's better not the do that with data migrations...
Ok, new question (others have been answered :)
i'm trying to run rake test:units. Everytime I run it, I think it build the test.db file right? Well my issue is that since my seed data is executed via rake db:seed RAILS_ENV=test, the rake test:units doesn't know that it should call it. So how do I short-circuit it so that it calls other stuff?
thanks
@Lateral Punk
What you want to do is put your test data into the fixtures -- see how AWDR does it.
You may be able to do: RAILS_ENV=test rake db:seed test:units . . . but, really, fixtures are the basis for testing.
http://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures
Hey John,
that last line sorta worked...but..the thing is that before a test/fixture is ran, it deletes all the rows in the table..so effectively, the rake db:seed is just evaporated!
Ok I know you are encouraging to put test data into fixtures, but the thing is my data isn't test, it's application data such as a look-up table e.g. status types. I figured if I put it in the seed stuff, it would work (and it does, the test path executes jsut fine), but then fixtures delete it all! I don't want to have a seed file that sets up my table and then a fixture that does the exact same thing and so I have duplication...
YOu see what I'm saying? I guess putting the tables lookups as data migration be best right ;)
@Lateral Punk
Let's ask Keith what he does.
Ok, but can we meet half-way?
I like what its mentioned in AWDR: Loading Data from Fixtures
Only thing is that they put a YAML file right in the migration dir...I don't want that. I want one place where I can share my table look-ups e.g. between application & testing...so what I think is that if I can get my data migration to load form the test YAML??? that would be awesome then?
Another question, can you recommend some plugin that allows to me to make unique codes? e.g. given some attributes like timestamp, length, weight,etc. make a style code that is unique...
HOw do you add an index to a table using migrations?
..eg. with script/generate migration..
Add a line like this to the migration file after you generate it:
add_index :table_name :column_name
(replacing table_name and column_name with the actual names of your table and column to be indexed)
@Ron Newman
Thanks, Ron. Note that sqlite doesn't support indices . . .
Yeah I was wondering if there was a short cut similar to the way you can add columns through migrations and it does the add_column thingie...thanks
I think I found something with the data migration that I'm happy with. This code allows me to share lookup tables between test & data migrations:
require 'active_record/fixtures'
class LoadContactInfoTypesData < ActiveRecord::Migration
def self.up
ContactInfoType.delete_all
directory = File.expand_path(File.dirname(__FILE__) + "../../../test/fixtures")
Fixtures.create_fixtures(directory, "contact_info_types" )
ContactInfoType.create_lookup_cacher :name
end
def self.down
ContactInfoType.delete_all
end
end
sqlite doesn't support indexes? I see these when I run the .schema command in sqlite3 on my development.db :
CREATE INDEX "index_comments_on_section_id" ON "comments" ("section_id");
CREATE INDEX "index_comments_on_user_id" ON "comments" ("user_id");
CREATE UNIQUE INDEX "index_courses_on_department_id_and_number_and_suffix" ON "courses" ("department_id", "number", "suffix");
CREATE UNIQUE INDEX "index_instructors_sections_on_section_id_and_instructor_id" ON "instructors_sections" ("section_id", "instructor_id");
CREATE UNIQUE INDEX "index_sections_on_course_id_and_term_id_and_number" ON "sections" ("course_id", "term_id", "number");
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
and these all appear to be the result of add_index statements in my migrations.
I only put the index in cause I'll be deploying this using MySQL later...
Q: this is confusing me now. how do you do a find that shows the columns from the join table? I tried :include & :joins and while they return the right rows, I want to see *all* the columns from both tables combined so that I can get more details out...
Ignore last question...
All my questions have been answered...
@Ron Newman
Hmm, I stand corrected.
My project uses e-mail and every time I send e-mail, either using SMTP or my local sendmail, the e-mail gets blocked by the Spam filter (I'm sending to my account on gmail.com) I've tried this (http://jonathansng.com/ruby-on-rails/rails-sendmail-and-spam-filters/) to no avail. Any suggestions?
Thanks
Andre
@Andre
What e-mail are you sending FROM, and what is the SMTP/sendmail server you're using?
As you will recall, in lecture I recommended sending via GMail as well (that is, NOT using local SMTP).
If you use the SMTP server or local sendmail on your own development machine, there's almost no way a reputable receiving SMTP server is not going to classify it as spam, because it isn't going to be able to do a reverse DNS lookup of your IP and have it check out.
@Andre
P.S. Looking at that post, the author is probably missing the big picture, which is that your SMTP server should have DNS properly set up, you should have DomainKeys or SPF set up, etc., etc. It's a big job to do that right -- so I would recommend sending via GMail.
@john
I tried sending through smtp.gmail.com with my credentials but got the same result - e-mail ended up in spam folder. The "From" and "Reply-To" are set the same.
Andre
While we are on this topic, I remember this being mentioned in class, but can't find notes on how/where we can redirect the mail through gmail. I assume this isn't too difficult, is there a quick link explaining the config somewhere - or did I somehow miss it in the slides?
Thanks!
Adam
@Andre
In my examples, here's what Mailer model looked like (notice: there's no messing around with headers, reply-to, etc.):
class NotificationMailer < ActionMailer::Base def publication_added(to_address) subject 'Thanks for adding a publication!' recipients to_address sent_on Time.now body :greeting => 'Dear ', :to_address => to_address end def annotation_added(sent_at = Time.now) subject 'NotificationMailer#annotation_added' recipients '' from '' sent_on sent_at body :greeting => 'Hi,' end end@AdamK
Here's what your settings should be for GMail -- this goes in environment.rb (if you want to use the settings for all environments) or in the specific environment files (e.g., environments/development.rb). (This should be in a lecture slide.)
change :user_name and :password as appropriate.
config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :smtp config.action_mailer.default_charset = 'utf-8' config.action_mailer.default_url_options = { :host => "localhost", :port => 3000 } config.action_mailer.smtp_settings = { :address => 'smtp.gmail.com', :port => 587, :authentication => :plain, :enable_starttls_auto => true, :user_name => 'john.g.norman@gmail.com', :password => 'PASSWORD' }I wrote a module with a bunch of methods to look up information on ISBNdb.com. I need to use this in my controller. Where should I put the module and how do I access it in the controller?
Thanks
Andre
@Andre
If you put a class called IsbnDb in lib/isbn_db.rb, you will be able to access it from your controller.
How do I validate form fields outside of ActiveRecord?
I have a form where the user specifies the number of copies of a particular book (model object Book). This number is used to generate copy objects, but it is not part of the Book object; however, I want to validate it nonetheless.
Thanks
Andre
@Andre
You should be able to add an attribute to the model (attr_accessor :my_extra_attr) and then validate it. But since it isn't mapped to the database, it won't be saved as such.
If I write a RESTful client, where should I put it? In the scripts/ directory, or in an entirely separate drop-box deposit? I assume this can just be a simple command-line program that retrieves some data from the website and displays it on the tty.
@Ron Newman
What I would do is put it in lib/
A catch here is that you may want the resource class name to be the same as the AR model, so there would be a conflict. If you really want the class name to be the same, then you would want to make a small separate project. Or you might put it into a separate module (Client::MyThingy).
The main reason to make it a separate project is: That's how you would distribute it to a customer.
By "separate project" do you mean a separate directory tree, with maybe just a bin/ subdirectory for the script and a lib/ directory for any classes I write that the script uses? I could just zip that up and upload it separately to the dropbox.
Since an ActiveResource project doesn't use most of Rails, seems like all I should have to do is put
require 'activeresource'
at the top of the file, and it should work anywhere.
@Ron Newman
Sure. If you include it in the main project, though, don't put it somewhere where the classloader can find it (otherwise you get the name collision). bin/ would be fine.
I have a quick question. Is there a way to make link_to behave like redirect_to rather then render? When i make a link lets say like this: link_to 'my name", edit_request_path(@request) it does not go through action but falls straight to the view
I ran into a really strange Ruby or Rails bug a couple of days ago.
My view template had this line in it:
which failed when the title was: "Courses taught by Alicia Campos Massó"
causing this error:
Encoding::CompatibilityError in Instructors#show
Showing app/views/instructors/show.html.erb where line #6 raised:
incompatible character encodings: ASCII-8BIT and UTF-8
Upon reading http://intertwingly.net/blog/2009/09/21/Ruby-1-9-and-Rails-3-0 ,
I changed the template code to this:
<h2><%= h yield(:title).force_encoding('utf-8') %></h2>and the error went away. But I don't understand why.
Especially since I didn't have to change my layout which also has a yield(:title) call in it.
You say:
but when I look at that Rakefile from Assignments 4 & 5, I see this:
t.package_files.exclude("#{db_dir}*.sqlite3")so it looks like I need to delete or comment out that line if you want "rake package" to include db/development.sqlite3 .
@Ron Newman
Comment it out.
@Lesha
It should always go through the action -- you might want to double-check the spelling of the action.
@Ron Newman
Ron -- regarding the incompatible character encodings:
In Ruby 1.9.x, you may have the problem that the page is being rendered as ASCII, but a String that is being interpolated "into" it is UTF-8. One way around this is to force the encoding of the page as UTF-8. I would probably need to study the specific case, but it might be fixed by putting
at the top of the template.
See http://blog.nuclearsquid.com/writings/ruby-1-9-encodings
I did put that line at the top of a couple of my migrations where I was inserting Spanish-language names into my database models. However, I don't know how I'd put that line into a view template without it being rendered as HTML (i.e. ordinary text).
@Ron Newman
I haven't studied this whole ticket -- but this seems to be the problem -- https://rails.lighthouseapp.com/projects/8994/tickets/2188-i18n-fails-with-multibyte-strings-in-ruby-19-similar-to-2038
Did anyone else run into the Encoding::CompatibilityError problem (described above) in your final projects ?
A couple weeks after I turned in my project, I imported the entire real Harvard Extension School catalog into my data model. I then had to add .force_encoding('utf-8") calls to a bunch more places in my views to avoid the Encoding::CompatibilityError when I navigated to various pages.
(The catalog has several course titles, course descriptions, and instructor names that contain accented non-ASCII characters.)