Final Project: Tips for the Writeup and Features
NOTE: We may well extend this page: Check occasionally for changes, which will be summarized by date at the top.
NOTE: Below: For the REST feature, you must implement nested resources.
Prefatory Words of Wisdom
- “What is the simplest thing that could possibly work?” (Kent Beck)
- “Don’t Repeat Yourself” (DRY - Dave Thomas and others)
- get it working first
- use good taste (if you get your code working, and it looks like a hairball, see if you can make it more understandable)
- Don’t forget it’s Ruby; write like a Rubyist
Please provide a writeup of what you have accomplished in the final project. Describe the application in terms of what the user experiences, and then in a separate section, you should explain how you did it. In other words, the writeup should have two sections:
- Use Cases
- Implementation
The easiest way to write is to think about your intended reader. For the use cases, the reader is someone who needs to know what is going to happen. The use case is essentially the “story” of the user experience, using the vocabulary of the application (For CCC: Users, Playdates, Invitations, etc.), just as we did for the assignment overview. That reader might be someone in QA, a VP of marketing, or someone who is evaluating your product. For the implementation section, the intended reader is another developer. Explain to that reader what they need to know to understand, maintain, and modify your code.
Your writeup is key. Oftentimes your grader cannot see what you’ve done unless you tell the grader. So “crow” about the compelling nature of your feature and the power of your implementation.
[Amy says: if you have a hard time figuring out how to write something of use to another developer, imagine telling someone in section how to do what you did, or complaining to them about all the things you had to try before you hit upon the thing that worked. Especially where your code is a little hairy or obscure, you want to explain why you did it that way instead of some other way that the other developer thinks, on first glance, would have been better. If the actual reason you did something was “I didn’t have time to do this any other way,” that’s still valuable information to provide, as it allows the future developer to distinguish between necessary and unnecessary complexity in your code. If you do not point out unnecessary complexity in your code, we will assume that you did not notice it, and from a grading perspective it is worse to do something nasty and not notice it than it is to do it and admit it. (Of course, it may just make sense to point out nasty bits in inline comments; not everything deserves a mention in your writeup itself. The point is not to leave ugly or ’smelly’ code in your project and hope we won’t notice it.) Think of your writeup as writing the first part of a good story about your project. You want the reader (QA, potential users, future developers, etc.) to be engaged, informed, sympathetic, and eager to be involved in the work of adding on to the story.
You DON’T want to write a sentence, run a word count, write another sentence, run another word count, and so on until you reach some magical length. If you tend to save the writeup until the very end and then sit staring at a blank screen wondering what to say, try keeping a log while actually at work on the project: jot down problems you’re facing, decisions you come to and why, expressions of frustration, notes about how long something took you to do, resources you found helpful, etc. Then when you get to the writeup you will have a wealth of raw material to use.]
Recall that we want you to include three features that adopt 3rd party plugins or go a bit beyond the standard model + controller + view framework.
After each feature, I will provide a bit in brackets that “scores” the feature in terms of difficulty, potential to learn, and value for the application (10 means high value, 1 means low value. E.g., “Difficulty: 3, Learning: 1, App: 10″ would mean not too difficult to implement, you wouldn’t learn a lot, but it would be a great feature for the user).
1. 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. 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. A really provocative and interesting emerging trend in web-based applications are those that read e-mail and restructure the data in the e-mail into something the application can use. For an example of this, check out TripIt (http://www.tripit.com/) — try it — you e-mail them a travel itinerary, and it reformats it into a page you can bookmark, and blends it with other trip-related data.
Setting up receiving mail may require access to a Linux system that is already receiving mail; or you might need to figure out how to get an an IMAP or POP e-mail store. I may be able to circulate some sample code for retrieving e-mail from GMail.
[Sending: Difficulty: 1, Learning: 3, App: 5]
[Receiving: Difficulty: 5, Learning 3, App: 5]
2. User management: Adapt the login / registration code to use the restful_authentication plugin (http://github.com/technoweenie/restful-authentication/tree/master). You should provide a means for the user to fully register (adding first_name, last_name, etc.). The best implementations will study the migration provided by the plugin, and will figure out a way to save the existing user data as it is migrated to the new scheme. This may be hard. NOTE: By itself, this is a pretty weak feature, because I provide a complete recipe in a screencast.
[Difficulty: 1, Learning: 1, App: 7]
3. OpenID, roles, or other significant extensions to restful_authentication. You may also find that your application can make good use of some of the extensions to restful authentication: For example, Railcasts has a nice demo for adding support for Open ID (http://railscasts.com/episodes/68) and there are extensions that provide for roles (e.g., http://code.google.com/p/rolerequirement/). NOTE: You may well find that blending the current version of restful auth with an extension such as OpenID or roles is hard. If you find yourself using up your time on this, move on to another aspect of your project. You should get restful auth working first, and make a backup copy of your work before trying some of the fancier options.
[Difficulty: 5; Learning: 5; App: 7]
4. 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 rewarded, as well as systematic and consistent use of Ajax throughout the application. The very best implementations would build a number of the following:
- Updating sections of the page dynamically as appropriate
- Replacement of a form with the results of that form after posting
- In-page asynchronous notification of events (e.g., for CCC, “Naomi has accepted your invitation for the playdate on 26-Dec-2007″)
Other tricks and features can be useful: In MetricsMine, we have a form over a table. When the form is submitted, the table below can be updated. It can be very cool to do this in Ajax so that the table silently updates. One neat thing people do with this kind of update is to use the “yellow fade” effect to highlight the item that has just been added (Google for “yellow fade” effect to learn more about this).
By all means, write e-mail to the course list if you have other ideas. Amy, Keith, Harlan, and I are not the biggest Ajax people, so we would likely learn from your ideas in this department.
The best implementations will also ensure that your app degrades gracefully for those users who have disabled JavaScript or may be accessing the app through a non-standard browser. Be sure to mention anything you do in this regard in your writeup. If you don’t ensure graceful degradation, your writeup should explain why you don’t think it’s important to do so in a way that your ‘product people’ will understand and agree with.
[Difficulty: 5; Learning: 5; App: 2]
5. REST. Provide a REST interface for two or more of your models. You must implement nested resources. Private data exposed through REST must be suppressed to an unauthenticated requester. 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) or create a second small web app that exercises the API.
[Difficulty: 3; Learning: 5; App: 4]
6. Add the ability to upload materials. You may use the strategy outlined in AWDR (pp. 501ff), or use the attachment_fu plugin (see this tutorial: http://clarkware.com/cgi/blosxom/2007/02/24#FileUploadFu). Another good option is paperclip (http://www.thoughtbot.com/projects/paperclip/). For image uploading, you may have to instsall RMagick or another image converter. A word to the wise: If you want to do image upload, you should test this very early in your development cycle, because the image processing plugins frequently require native extensions and the like (in other words, they’re hard to install).
[Difficulty: 3; Learning: 2; App: 4]
7. 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. The best implementations will generate feeds that are actually interesting in light of what the application does.
8. Asynchronous jobs: Manage tasks through Workling (http://playtype.net/past/2008/10/2/workling_version_03_released/) or something similar. There are times when you need to perform a compute-intensive task, such as image manipulation or significant database work. Workling (and other modules similar to it) provide a means to have that work be done outside of a regular request. You “fire off” the Workling job, and it might, when it is finished, update a row in your database so that you know that the work is completed.
[Difficulty: 5; Learning: 3; App: ?]
9. Time zone handling. See http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/. The idea here is that all time data is stored in the database in UTF, but you allow your users to pick any time zone they want for display. We wouldn’t give you credit for the following, but there are interesting tricks you can do to figure out the time zone of a visitor to your web site (see http://stackoverflow.com/questions/13/determining-web-users-time-zone).
[Difficulty: 3; Learning: 2; App: 3]
10. 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. There is a recent screencast from Railscasts.com on how to get started with this. If you really want to do this and your TA approves, you may want to upgrade to Rails 2.2.2 for this.
[Difficulty: 7; Learning: 6; App: 9]
11. 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.
[Difficulty: 6; Learning: 6; App: 9]
12. Mashup of two public APIs. For this, you would access two services via SOAP or REST, and blend them together in an interesting way. To get a sense of what’s out there, see http://www.programmableweb.com/matrix. These kinds of projects may get pushback from the TA’s, because they can be hard to implement.
[Difficulty: ?; Learning: ?; App: ?]
13. Something else. You must get approval from your grader. If you discover something you really want to try, we will consider it, though our bias will be to say “no” at this late date.
[Difficulty: ?; Learning: ?; App: ?]
blog comments powered by Disqus
Add New Comment
Viewing 65 Comments
Thanks. Your comment is awaiting approval by a moderator.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
I know the course is long over, and no-one may read this.
Is there anyway to compile my ruby code into some sort of Bytecode that can't be read / modified / stolen? Like a Java .class file.
I'm getting a web designer to spice up my final project site (www.movie-cat.tv) and want to protect my code. I know how I could do this with the filesystem protections on Linux on my web server, but don't necessarily want him working on my live server.
Thanks,
Raj
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Length: You have to explain how your app is designed, how it works, and how it needs to be maintained. Imagine a document that would describe such things for an app of similar complexity not written by you. It strikes me that it is hard to imagine that it would be fewer than 4 pages, but everyone writes with different degrees of concentration and pithyness.
Your TA is not going to be able to grade two projects. You are going to have to submit one ZIP that represents what you want to have graded.
Do you already have an account? Log in and claim this comment.
In my app when i type http://localhost:3000/ and I get "Welcome aboard: You're riding the Rails!" I have the following line in routes.rb file in config directory. It is the first line.
map.connect '', :controller => 'welcome', :action => 'welcome'
If i type http://localhost:3000/welcome/welcome, everything works fine. It displays the main page. What is going on. I am confused.
Thanks
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Harlan taught me how to use named_scope last night in the clinic, but its causing some issues. Couldn't find anything useful about it on the interwebs.
Here are my named scopes for my "Movies" class:
named_scope :all, :order => "name"
named_scope :rated, :order => "name", :conditions => "rating > 0"
named_scope :new, :order => "name", :conditions => "url = 'recentlyadded'"
plus a few more...
Now, in my other classes, when I try to do this:
temp = Movie.find_by_name(newname)
if (!temp || !temp.year)
puts "LOOKED UP " + newname + " AND DECIDED TO SAVE"
mov = Movie.new
mov.name = newname
mov.rating = 0
.....
I get:
undefined method `name=' for #<Class:0x81cf34c>
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1672:in `method_missing'
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/named_scope.rb:158:in `send'
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/named_scope.rb:158:in `method_missing'
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1857:in `with_scope'
(__DELEGATION__):2:in `__send__'
(__DELEGATION__):2:in `with_scope'
app/controllers/scrapers_controller.rb:79:in `scrape_comcast'
Why is Scope coming into play here? I'm not using it in this particular class. does "scope" stick around in some way?
(i also changed the first line to "temp = Movie.all.find.....)" to no avail.
Do you already have an account? Log in and claim this comment.
So for:
named_scope :new, :order => "name", :conditions => "url = 'recentlyadded'"
Call it:
named_scope :recently_added, :order => "name", :conditions => "url = 'recentlyadded'"
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
I am running into something strange with a link, I have the following code in my one of my views
<td><%= assign.name %> <%= link_to '(edit)', :action => "edit", :id => assign.id %> </td>
I expect link to be (edit)
but it keeps rendering as (edit)
It is the action and id are reversed for some reason? Has anyone ever seen this?
Do you already have an account? Log in and claim this comment.
I expect the link to be
href="/assignments/edit/1">(edit)
but it gets rendered as
href="/assignments/1/edit">(edit)
Any ideas?
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
As I said before, paste in your entire routes.rb file.
If you go back through the lectures, I demo'd adding an Atom feed with a RESTful controller.
Do you already have an account? Log in and claim this comment.
So yes, you should use map.resources :assignments, and it will give you urls in the format you posted, which are the standard RESTful Rails routes.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
map.connect '', :controller => 'welcome', :action => 'index'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.login '/login', :controller => 'sessions', :action => 'new'
map.register '/register', :controller => 'users', :action => 'create'
map.signup '/signup', :controller => 'users', :action => 'new'
map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate', :activation_code => nil
map.resources :users, :member => { :suspend => :put, :unsuspend => :put, :purge => :delete }
map.resource :session
#atom feed related config
map.resources :assignments
map.root :controller => :assignments
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
Do you already have an account? Log in and claim this comment.
I am suddenly aware of a very different kind of technology around me. My project has a plethora of complex database table relationships, and yet I have not written a single line of SQL, nor do I plan to. My paramount (read "only") concern has been to architect the perfect set of related Objects (tables), and then Ruby (actually Rails) enables my journey from there.
Is this what is meant by the phrase "a pure object oriented language"?
Is there any other language or web environment that even comes close to enabling this extreme "crystalline structure"?
As a follow-on question, "What would / will be the situations where I will write SQL in a RoR project?
- to optimize the load time of a GET page that displays a very large set of data? So if Rails was looping over a group of thousands of individual SQL "select" statements, then I might need to write a single query to pull the same data?
- to prevent a similar looping over a large number of PUT "updates"? So if I had to change an index across a large number of records (although, in my experience, this type of thing is usually done as a one-off administrative task directly in an Enterprise Manager interface)?
- what other times will I write SQL?
I am struck by something one of the Expert Panelists said at John Harvard's (can't remember which one, due to the blur or beer). I have spent the past twelve years of my life coding complex data-driven sites in ColdFusion. The Panelist said "I can't imagine having to maintain someone else's ColdFusion code for such a site." Indeed there is no crystalline structure (other than the cumbersome "Fusebox" system) where all the logic is laid out intuitively as in RoR.
Where *else* is this taking me that I cannot even envision yet?
This is a totally different way of thinking...
Josh
Do you already have an account? Log in and claim this comment.
I already have two HABTM's in my project (Movies <=> cable providers, and cities <=> cable providers). All the docs i'm reading are making me want to create a third (movies <=> genres ) But I know I could do this another way that involves more controller code. How good / bad are habtms?
Do you already have an account? Log in and claim this comment.
If you find that you need to have a model representing the join table, then you should have a model where each instance "belongs to" two different other tables. Then you would use has_many :through to get across the join table. See AWDR.
My personal experience is that habtm associations usually turn into has_many :through, so I tend to avoid habtm. Your data model, however, may be perfect for habtm.
Do you already have an account? Log in and claim this comment.
http://localhost:3000/categories/new?parent_id=17
and trying to get that "params[parent_id]" to get defaulted in a pull-down menu on the page. If I remember correctly then I should be setting the incoming parameter in the CategoriesController something like the following.
def new
@category = Category.new
@category.parent_id = Category.find(params[:parent_id])
...
end
and then picking it up on the new.html.erb page as
@category.parent_id
but it is not working
Please help.
Do you already have an account? Log in and claim this comment.
Jody
Do you already have an account? Log in and claim this comment.
Take a look at collection_select - http://api.rubyonrails.org/classes/ActionView/H...
The collection param is for all of the items you want to show in the drop-down.
Then to get it to pre-select the "old" item, you should pass in a reference to that old item as the first param. Then the second param is the attribute (or method) that gives the id for that "old" item.
Do you already have an account? Log in and claim this comment.
<% form_for(@category) do |f| %>
<%= tree_select(Category.find(:all, :conditions => "parent_id = 1"), 'category', 'parent_id', @category>
<% end %>
The code loads, complete with the tree select menu, but did not preselect the item from the menu.
Per Jody's comment I got the parameter to display on the page, outside of the "tree_select" tag. So that test worked, but I just could not figure out how to assign it into th "tree_select" tag variables. But at least I had a "toe hold"... thank you.
So I hacked into the "application_helper.rb" template, and found the following code that is supposed to apply the wanted 'selected="selected"' parameter to the pull-down menu option:
html << ' selected="selected"' if cat.id == selected.id
I am not sure where that "selected.id" variable is coming from. However, it was not being activated in this "action=new" scenario (probably it is only activated in the "action=edit"), so I just added a second line right after it referring to my "@parent_id" variable (which I defined in the "new" method of "categories_controller.rb" as equal to the incoming "parent_id" URL parameter). So there are two lines right next to each other as:
html << ' selected="selected"' if cat.id == selected.id
html << ' selected="selected"' if cat.id == @parent_id
This seems to work for now, for both the "action=new" and "action=edit" scenarios.
However on Wednesday, maybe I can get a little help refining... figuring out how such custom addon tags should ideally be configured. I would like to review how I have implemented a few different "tree" functions.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Jody
Do you already have an account? Log in and claim this comment.
Thank you for following up though. Your help is appreciated!
Do you already have an account? Log in and claim this comment.
You could still get decent mileage early in a project by combining it with grep and just changing directories, I guess.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Not really. Your text editor may provide a means to do a global search-and-replace over an entire project -- or on Linux you may Google for a strategy to do this over a directory tree. If this is for the final project, my advice is to leave it as is.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
-- Delete from the console. E.g., Thing.delete(1) # where 1 is the id of the Thing you want to delete. Remember the difference between delete and destroy from lecture -- destroy uses the callbacks, so if there are dependent objects, they will get deleted, too.
-- Play around with your app, then delete the development database (in db/development.sqlite3) then re-run your migrations. This is the cleanest way.
Do you already have an account? Log in and claim this comment.
Here is the URL for it.
https://addons.mozilla.org/en-US/firefox/addon/...
Yes, migrations are the coolest way. One issue I would love to figure out is as follows. One needs to create "data_add_...rb" migrations (in the "root/db/migrate" directory) to replace the core data table records every time you migrate a rebuild. Is there is an easy way to create such "data_add..." migration files. I have been hand coding them. For instance with "SQLite Manager" and many other databases you can export data in different formats (CSV, XML, etc). It would be great if there was a tool whereby one could export data from a table and it would create such a "data_add...rb". Then you could build up a set of data, and keep a snap-shot of it for future migrate rebuilds. Maybe such a page can be coded directly in Ruby / Rails code, as an "administrator" function on the site?
Do you already have an account? Log in and claim this comment.
http://nubyonrails.com/articles/dump-or-slurp-y...
I think this is what I used to create the fixture "test" data for the "data" milestone of the Metrics app.
Note that restoring a database properly requires you to load the tables in an order such that any constraints are not violated. For Sqlite3 this shouldn't be a problem, but it can be tricky for databases that enforce constraints. Typically the database would offer some means to turn off all constraints during a restore, and then turn them back on.
Do you already have an account? Log in and claim this comment.
Note that you don't use the actual name of the table, which is always plural, but you use the singular noun, and keep it capitalized. Also a join table like "groups_users" gets dumped with "GroupsUser.dump_to_file".
Is there a way to make the ".yml" files to automatically "load_from_file" when the migrations are run? Otherwise the data has to be reloaded into each table individually. I tried pasting the content of the ".yml" file into the migration file, but it was not formatted correctly.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
ruby script/runner "User.dump_to_file"
and the migration file will just put everything from that YAML file into the table.
That is just perfect. Nice.
Do you already have an account? Log in and claim this comment.
You can also set up test data as yml files in test/fixtures and use the command rake db:fixtures:load to build your database. If you've got good data that you want to use (and you aren't doing any testing), you can dump all of your data into yml files (users.yml, companies.yml, whatever your table names are) and use that command at any time to get a fresh set of data.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
My personal favorite is http://www.slicehost.com/, which I used in the deployment screencasts. They have a really good wiki with detailed instructions to get set up; I've never had a server go down, and the prices are reasonable. I've never had to call them. I have also heard good things about http://rimuhosting.com/
This site is hosted at slicehost.com. I've never had a problem. I'm running on the cheapest plan.
Other options people like: http://www.engineyard.com/ http://railsmachine.com/
The systems described above typically run Xen virtualization; they run multiple virtual hosts on a single piece of hardware, and you get a defined "slice" of memory, CPU, disk, etc. To you, they look exactly like a dedicated system (so you can reboot, etc.). There are also VPS providers for Windows, but I have no experience with it, and wouldn't recommend Windows for a production Rails site anyway.
If you have serious virtualization needs, you might look at http;//joyent.com
Finally, there's Amazon EC2. That's what we use at my company, and at my previous company. A "small" instance at Amazon is about $75/month, but the great thing about Amazon is that you pay by the hour (e.g., $0.10 / hour) so if you need an extra server for a day, you can allocate it, use it, and destroy it, for only $2.40. EC2 would require someone knowledgeable to get you set up: It's great, but you have to be something of a mechanic. There is likely phone support, but it's not included (to my knowledge) in the per-hour pricing model. Amazon has a lot of great add-ons such as virtual disks, a queuing system, etc., that become useful in the "real world."
In any case, slicehost.com has been low friction for me. They were recently acquired by rackspace.com
Do you already have an account? Log in and claim this comment.
when I generate a select box from a collection, it seems to generate the html exactly as I would like.
I then do this in the controller....
@admin = Admin.new(params[:admin])
In debug mode, I check the params[:admin] and company_id is there, spelled correctly, and matches the spelling in the database. It won't save no matter what I do so I have to follow it with this line:
@admin.company_id = params[:admin][:company_id] if params[:admin][:company_id].length > 0 #company_id won't save so I have to do it manually.
Any ideas?
Jody
Do you already have an account? Log in and claim this comment.
(1) Double-check that the REST of the Admin object is correct -- it may be that for whatever reason something else in the object is invalid.
(2) What is the code you're using in the view? In booksindex, we use:
<%= f.select("book_id", @books.collect {|b| [ b.title, b.id ] }) %>
Look at the console log (not debug mode) and see what is actually going into the params Hash (i.e., everything, not just params[:admin]). Compare what you are seeing with select box examples from the sample applications. A good example is in booksindex in app/views/index_entries/new.html.erb and app/controllers/index_entries_controller.rb in the create method.
Do you already have an account? Log in and claim this comment.
http://localhost:3000/groups/2/edit
which when clicked cause an error like this:
Unknown action
No action responded to 2
If I change the url manually to
http://localhost:3000/groups/edit/2
putting the "/2" AFTER the "/edit", then the page comes up just fine.
How do I get the urls to automatically have this second format?
Here is the "helper" format I am using:
= link_to 'Edit', :action => :edit, :id => group.id
I am not sure why this suddenly started happening. The urls were working before.
Do you already have an account? Log in and claim this comment.
map.resources :groups
Do you already have an account? Log in and claim this comment.
So the resources were mapped automatically by the scaffolding that I did! Not only that but all of the scaffolded ".html.erb" templates use buttons with mappings in them. Here is an example of the "New" button that is on the end of my "Groups" templates
= link_to 'Back', groups_path
= link_to 'New group', new_group_path
When I remove the resource mappings from the "routes", then I get errors from those tags as follows:
undefined local variable or method `groups_path'
How did these resource mappings happen? And the mapped-style "link_to" tags get deployed?
More importantly, what should I do now? What is the preferred format? Should I get rid of the resource mappings?
Do you already have an account? Log in and claim this comment.
The resource mappings and link_to tags 'happened' when you used the scaffolding.
Do you already have an account? Log in and claim this comment.
Is there some philosophical reason why ":controller/:id/:action" is better?
Does this tie out at all with ReST?
Is this the [current] envisioned future of rails, to use the "resources"?
Is this seemingly major shift in routing important for us to know about?
Did we discuss this in class at all, and if not then why not?
I am pretty "fired up" about this issue... Sorry for all the questions.
= ; )
Josh
Do you already have an account? Log in and claim this comment.
If you compare the routing and controllers in LinkWizz versus BooksIndex, you will see the contrast.
In lecture, we spent a lot of time on manually building controllers and views for the "classic" :controller/:action/:id routing. Frankly, I can't see how anyone can understand the REST-style of development without this prior learning. For REST, the framework does so much for you that if you haven't done it manually, it's easy to get lost.
THEN across two lectures, I discussed routing and REST. This is when I used the script/generate scaffold to create the controllers and routing. Those controllers expect REST-style routing, rather than :controller/:action/:id. If you have some controllers you've created manually, you can still use the :controller/:action/:id routing.
:controller/:action/:id is not "better." It is simply a convention. It is a good way to organize the behavior of your application so that you can see action names and ids on the URL in a way that conforms pretty tightly to the way you would organize your controllers if you are used to conventional web development.
The current and future use of Rails stresses REST, and especially for parts of your application that can be represented as nouns (i..e., things that can be "resources"). Once you set up your app in REST-fashion, then you get standard URLs for all of the "CRUD" operations. All of this was covered in lecture, and, of course, is addressed at length in the Agile Web Development with Rails book.
Do you already have an account? Log in and claim this comment.
I apologize if I raised your hackles, John, by proposing that you had not discussed this in class. I do remember your scaffolding lecture quite vividly, but totally missed one dramatically important issue... as follows.
Is it correct that one cannot combine both of these routing methodologies into one application? They seem to totally conflict. Because the URL-positions of the :ID and :ACTION get swapped, Active Record cannot figure out how to handle both types of requests. (Is there some way to combine both?) This must have been a huge "shift in the force" in the evolution of Rails. Why did the RESTful "resources" methodology swap the URL positions of the :ID and :ACTION? If the ":controller/:action/:id" URL format had been continued (as I am thinking it should have been), then there would not be this astonishing chasm between the two methodologies.
I concur with the statement that "I can't see how anyone can understand the REST-style of development without this prior learning". There are no IDs anywhere in the helper tags! That is tough to get my intuition around.
Last night I was in the process of re-writing all my code in the "classic" style, but now am pretty sure I have to revert back, and take on the RESTful "resources" approach.
I am thinking that when we did assignment 3, re-building the disabled LinkWizz application, that we should have focussed on this RESTful "resources" method. Isn't that the future of Rails? That was my (our) springboard into the current Class Project.
Whereas I relish new things, I also get unnerved when new paradigms totally obliterate what people have struggled to master. I imagine that there was a really good reason for this paradigm shift in the history of Rails.
Again, I am sorry if I am "raising your hackles". This is rocking my world in a couple of ways.
Thank you again for the discussion.
Do you already have an account? Log in and claim this comment.
"Not all routes are created equally. Routes have priority defined by the order of appearance of the routes in the config/routes.rb file. The priority goes from top to bottom. The last route in that file is at the lowest priority and will be applied last. If no route matches, 404 is returned."
I agree with John that you've got to understand how things were done prior to REST in order to understand how to work with resources. With a resource, you aren't swapping the id and the action -- in some cases you aren't even specifying the action, since the HTTP header determines what action is used. See http://api.rubyonrails.org/classes/ActionContro... and the chapters on this in AWDR.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
will the following work:
model_clinic
-- has_many users
-- has_many staff through user
-- has_many patients
model_user
-- has_one staff
-- belongs_to clinic
model_staff
-- belongs_to user
-- has_many patients through clinic
the last association in the staff model is the questionable one. Can rails find it's way back to the staff model through the clinic model in order for all the 'magic' to work or does it need a more direct association?
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
The patient model would look like this:
model_patient
-- belongs_to clinic
Please note that there are other models that I have not mentioned, and there are associations to those models in these models (and vice versa), but they handle other aspects of the application.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
So the key is this:
On each end (staff member and patient) they need to have something in common.
So, for example, it might be like this:
A staff member has many appointments
A patient has many appointments
So an appointment belongs to a staff member; and it also belongs to a patient.
Now you can have:
A staff member has many patients through appointments
A patient has many staff members through appointments
and the like.
See pp. 182, 351 in the latest PDF of AWDR.
Do you already have an account? Log in and claim this comment.
I'm guessing that's from last year?
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Add New Comment