e168f08: Final Project: Tips for the Writeup and Features
hogganbeck
· 1 year ago
"If you are adapting Assignment 5 for the final project, you may only use one self-defined feature."
I'm guessing that's from last year?
jgn
· 1 year ago
Eh? :-)
hogganbeck
· 1 year ago
Wow. That must be some of that fancy Rails magic I keep hearing about.
jgn
· 1 year ago
It's the mind-reading + auto-correction plugin. It's an alpha release -- doesn't always work.
DanielS
· 1 year ago
A quick question about has_many through:
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?
jgn
· 1 year ago
Is a user the same as a patient? If so, re-paste your work so it's consistent. If they're not the same thing, add a patient model and re-paste that . . . then we can see.
DanielS
· 1 year ago
They are not the same. The intention of the user model is to break staff (doctors,nurses) information away from login information. The user model will contain things like login, password, role, etc. The staff model will contain things like doctor name, provider ID, etc. This allows me to provide users who are not staff members. An example of this would be a superuser who would add new clinics and configure various settings, but who is not necessarily a doctor or a nurse. It would also allow me in the future to provide patients with logins (though that is not in scope at the moment).
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.
jgn
· 1 year ago
The staff model: Do you mean, perhaps, "StaffMember" (singular -- as model names should be)?
DanielS
· 1 year ago
hm. yes that would work. I was having some trouble with the singular form of staff. :-)
jgn
· 1 year ago
OK.
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.
swithin
· 11 months ago
I am running into what is apparently a "routes" issue. My "edit" links are of the format http://localhost:3000/groups/2/edit which when clicked cause an error like this: Unknown action No action responded to 2
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.
swithin
· 11 months ago
Even the form actions don't post like they used to. The "update" / "edit" forms all used to work just fine. Now they just lead to the "index" page, with no changes being made to the record being edited.
Keith
· 11 months ago
The second case is matching the default routing, ':controller/:action/:id.' This is the expected behavior, unless you have specified something else in your routes.rb file. If you want to have the form '/groups/2/edit' you would need to map a resource in routes.rb, like so:
map.resources :groups
swithin
· 11 months ago
That matches what I thought.
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?
Keith
· 11 months ago
Use the mapped resources. By creating those resources in your routes.rb file, you automatically get a bunch of paths/urls for free -- use 'rake routes' to see what you have available. If you remove the mappings, well, those routes that you got for free are removed, and you'll get the 'undefined local variable..' method.
The resource mappings and link_to tags 'happened' when you used the scaffolding.
swithin
· 11 months ago
Why the ":controller/:id/:action" rather than the, as you called it "classic", ":controller/:action/:id"?
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
jgn
· 11 months ago
All of this was covered in lecture and in example code.
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.
swithin
· 11 months ago
Thank you very much for this explanation from both of you.
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.
Keith
· 11 months ago
You can use both of these routing styles (and many more) in an application. (Also, this has nothing _at all_ to do with ActiveRecord.) From the routing docs:
"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.
Jody
· 11 months ago
I'm running into what seems to be a rails bug. It seems I've found a few rails bugs with select boxes.
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
jgn
· 11 months ago
Yes.
(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:
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.
swithin
· 11 months ago
What are the best Ruby on Rails web hosts, in your opinions? Not the cheapest, but the best. I have been hosting many ColdFusion sites at CrystalTech for going on a decade now. They are not the cheapest, but they answer the phone 24 x 7 (or call back quickly), and have intelligent people doing support as part of a highly functioning team. For example, I do a "elective community action" web work late at night, after I get home from my day job, and might need help troubleshooting an email routing issue at 2am. I would love to find a Rails host that I could be happy with for the next decade. Thoughts?
jgn
· 11 months ago
My personal feeling is that shared hosting (as at, say, http://www.dreamhost.com/ -- shared hosting is pretty common in the ColdFusion world) is not a viable option for Rails deployment -- you need control of an entire system, which means that you need a VPS or a real machine.
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.
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."
Let's say I've entered in some data into my application that I would like to delete without using my application for debugging purposes. What's the best way to delete data I've entered from the database? The console?
jgn
· 11 months ago
There are a lot of things you could do:
-- 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.
swithin
· 11 months ago
I have been using the "SQLite Manager" add-on for Firefox for a few months now. Very cool Highly recommend it, especially if you're a Firefox user. You can easily highlight all the records in a table and click "Delete Selected". You can also modify the structure of tables (though you need to keep migrations up to date). Even has access to Views, Indexes, and Triggers... didn't know SQLite had those. Lots of nice things in this Firefox add-on.
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?
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.
swithin
· 11 months ago
This plugin took less than 5 minutes to load, and worked like a charm. The "Table_singular.dump_to_file" and the "Table_singular.load_from_file" work great.
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.
jgn
· 11 months ago
No, you would actually have a migration to load from file, and do Whatever.load_from_file and the like. This is what you want, anyway, because you want to isolate the data loading in a specific migration.
swithin
· 11 months ago
I suddenly had a flash of this when at dinner. Maybe your blog post flew into the restaurant. Yes, this is very cool. So whenever I want to update the mirror of a particular table of data in the migration, then I just rerun the command 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.
Keith
· 11 months ago
Alternative solutions here are to add a rake task (they can be automatically loaded from lib/tasks) that you can run at any time to populate your database for you. That way you can 'build up' data that matches the current schema, rather than having to continually write new migrations and migrate up / down as necessary.
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.
swithin
· 11 months ago
Let's say I wanted to change the Users object to People. That would mean the words "Users", "User", "users", and "user" would need changing in file contents and file names everywhere. Is there an easy way to do that in a fail-safe way?
jgn
· 11 months ago
I assume you mean: User and Person (models are singular, tables are plural).
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.
Keith
· 11 months ago
sed makes this really easy. There is a port of sed for Windows; I've never used it, but if it works the same way as it does for Linux it makes this truly easy.
jgn
· 11 months ago
How do you do the recursive traversal of directories with sed? Do you have to use Unix "find" in conjunction with ti?
Keith
· 11 months ago
Yes. I was just thinking 'oh, use sed!' and not really thinking about find.
You could still get decent mileage early in a project by combining it with grep and just changing directories, I guess.
swithin
· 11 months ago
I am hitting 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.
jgn
· 11 months ago
There are a lot of ways to get what you want. I would suggest that you look in AWDR for examples of "select" usage.
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.
swithin
· 11 months ago
I apologize that I did not give you all the information you needed to help me on my issue. I am not using the standard "collection_select" to generate this pull-down, but rather a custom addon "tree_select" tag that I installed. It sits in the form_for as follows: <% 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.
Jody
· 11 months ago
Just one more thing you might want to look at. I ran into problems with a custom control expecting my to convert my param to a string and I was passing in the integer value. Probably not your issue but just in case.
Jody
swithin
· 11 months ago
Thank you, Jody. Yes, I ran up against that, but did not have to do "mortal combat" with it. I just put the ".to_i" extension on the value of the variable that I set.
Thank you for following up though. Your help is appreciated!
jgn
· 11 months ago
Make sure to discuss the use of custom components with your TA . . .
Jody
· 11 months ago
Have you tried just printing the variable out on the screen in the view to make sure it's getting through? If it is, then the professors option is a great one. Another thing you might want to read is the prototype javascript section in the book. I found that prototype was great to easily set a default in any field on your page. It requires javascript though.
Jody
rajatbaner
· 11 months ago
Are there customs regarding how often you use HABTM? I really like using it but i'm wary about overusing it since it stores so much additional info in the DB. The same stuff is usually possible by using a join statement.
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?
jgn
· 11 months ago
If you believe that the "join table" contains no model-style information, then stick with habtm.
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.
swithin
· 11 months ago
"Where is Ruby taking me?"
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
akv
· 11 months ago
Hi,
I am running into something strange with a link, I have the following code in my one of my views
#atom feed related config map.resources :assignments map.root :controller => :assignments
map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end
akv
· 11 months ago
y, i took that out and it's working for the edit but do I need the map resources :assignments for the atom feed? I was following an example on the ruby on rails site and it said to add it there. Also, why does it it cause problems if it is in the map.resources?
jgn
· 11 months ago
map.resources :assignments should result in the link_to helper generating links in the "RESTful" for (/assignments/edit/1).
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.
Keith
· 11 months ago
Actually, it would be /assignments/1/edit, as akv posted :) ':controller/:action/:id' is the default routing, not a RESTful route.
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.
jgn
· 11 months ago
Sorry, wires crossed.
rajatbaner
· 11 months ago
Hi, 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.
jgn
· 11 months ago
Don't use the name "new" for a named scope -- you don't want to override the normal object initialization do you?
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.
As I showed in every single app creation demo, you must delete public/index.html (or rename it). Otherwise, this static file will be picked ahead of your controllers, etc.
na
· 11 months ago
Thanks John.. I always do the same mistake.
Anonymous
· 11 months ago
In the final project description there is a hint at more information on the write up. Is this available somewhere? If not is it OK to ask how long this write up should be? Another question - I have reached a certain working point in my application . If I proceed to implement another feature, I'll break the functionality. If I have not finished by the end of the day, may I submit 2 ZIP files, 1 working - 1 work-in-progress ? I wish there was a single posting forum - I just discovered this thread today.
jgn
· 11 months ago
About the writeup -- this very page is the extra info on the writeup.
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.
rajatbaner
· 9 months ago
Hi, 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
I'm guessing that's from last year?
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?
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.
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.
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.
map.resources :groups
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?
The resource mappings and link_to tags 'happened' when you used the scaffolding.
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
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.
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.
"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.
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
(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.
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
-- 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.
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?
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.
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.
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.
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.
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.
You could still get decent mileage early in a project by combining it with grep and just changing directories, I guess.
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.
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.
<% 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.
Jody
Thank you for following up though. Your help is appreciated!
Jody
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?
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.
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
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?
I expect the link to be
href="/assignments/edit/1">(edit)
but it gets rendered as
href="/assignments/1/edit">(edit)
Any ideas?
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
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.
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.
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.
So for:
named_scope :new, :order => "name", :conditions => "url = 'recentlyadded'"
Call it:
named_scope :recently_added, :order => "name", :conditions => "url = 'recentlyadded'"
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
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.
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