@Tony
One way to work with pdf is to use the iText java library with a ruby java bridge.
http://blog.codeinmotion.com/index.php/2006/12/22/pdf-generation-in-ruby-on-rails/
Just to assure you that you're making the right choice: Indeed.com is showing that there are now more Ruby jobs than there are Cold Fusion jobs:
http://prfsa.com/post.rhtml?title=ruby-passes-coldfusion-at-indeed
The CSRF protection in Rails 2.0 seems to break this approach, at least for me. When attempting the destroy thru JavaScript, it throws a ActionController::InvalidAuthenticityToken error. Without JS, of course it works.
My main issue with Rails 2.0 is that I don't have any idea how to get my Rails 1.2.x apps to work without disabling CSRF altogether. That seems a little heavy-handed, but I haven't been able to figure out a more elegant solution. Maybe I'm just ignorant of something obvious?
You screen casts are the best. I've learned so much from them as I'm attempting to move from ColdFusion to Rails.
There are only two things that are stopping me from making the move and maybe you can shed some light on them and they could be cool ideas for future screen casts.
First - In CF creating a PDF from a webpage is dead easy using the CFDOCUMENT tag. I've watch episode 78 on creating PDFs but it was very clunky at best. Plus you couldn't just pass in a variable containing the HTML to render and have it print out in the PDF. Do you know of any plugin or way to do this?
Second - Database views are never mentioned in any related to rails. Sometimes database views can be invaluable. Take this situation for instance: Suppose you have to get data from two different databases and mash them together. Out of the box ActiveRecord doesn't support multiple databases (though there are plugins that handle this). What you could do however is write a view that grabs the data from both databases and mashes it together.
So my question is: Is there anyway to tell ActiveRecord to create a class file for the view?
<% my_box do |box| %>
<% box.head do %>
...
<% end %>
<% box.content do %>
...
<% end %>
<% end %>
As you see its going to wrap some HTML for a rounded box.
I tried for several hours to find a solution. The main problem is that i cant capture the contents of the block.call(some_function) method. It always outputs everything to the template immediatly.
"Sexy" is my new least favourite coding buzzword... but good to see the new Rails 2.0 migrations keeping things so damn sexy ;) And the rake tasks which will save me jumping into phpMyAdmin for each new db not to mention the neat generators... as they say: if you have to do something twice - automate it!
wouldn't it be more consequent to write:
script/generate migration add_description_to_tasks description:string -
so tasks instead of task?
(works also) - as we have create_tasks (in plural)...
(same for remove obviously).
I just want to say "thank you". I'm new to rails and I like it. Your screencasts are great. I don't understand each of them fully, but from day to day I understand more.
Hi there, i have managed to implement updating the two models at once and was wondering if it is possible to do three? The third model im using (facilities) habtm the second (room_types). Ideally i would like to be able use check boxes to update the data. Any ideas?
Why create a method on map when you could simply send the actions to the map object?
def controller_paths(controller,*actions)
actions.each do |a|
map.send(#{controller}_#{a},#{controller/a},:controller => controller, :action => a)
end
end
how could i go about reversing the whole thing, so if i had posts from Descember and November, it would show:
December
...
..
November
...
..
October
etc?
@gorn I'm not certain that's the correct solution. I am on a pretty edgy version of Rails (well past 1.2.3) and I am getting this issue as well. Maybe it's the specific version that I am on that is messed up.
Does anyone else have any answers to the dreaded instance variable not found issue?
@sandro, the "_product.html.erb" partial only contains the html to display the product - not any form/fields to edit a product. I did not put form fields in a partial for simplicity sake, but you would likely want to create some kind of "_form.html.erb" partial for that.
@mikem, I have a test helper method which does the login process. I just call that at the beginning of any test which needs to login.
This login method can do several things. One is to mock the @controller.current_user method to return an account of your choosing. Another is to load a fixture record if you're using that.
You are absolutely right. To elaborate a bit more for nelson jr, with HTTP Basic Authentication and REST you won't need to use a server-side session at all. The server authenticates you and services your request. You then cease to exist to the server, as you are not actually "logged in".
This makes running a service/site across a cluster or servers simple because your session state (logged in, not logged in etc) isn't of any concern. A subsequent request could go to any server in a cluster and it wouldn't be a problem because you provide your authentication details again.
This is a very handy little tip, thanks. Keep up the good work with the casts too.
Just one question: How would you go about producing a list of the months so that every month of the year was listed whether it has anything to group under it or not? (Does that make sense?!?!)
@nelson jr: As opposed to the "normal" way of authenticating, where you set session[:user] to something (which is what e.g. the restful_authentication does), this particular method authenticates you if the stuff inside the block returns true. So, doing this would authenticate you:
authenticate_or_request_with_http_basic { true }
This is what a User.authenticate action could look like:
def self.authenticate(username, password)
user = self.find_by_username(username)
user && user.valid_password?(password)
end
This method returns true if a user was found and the password was valid. Otherwise, it returns false (if the password wasn't valid) or nil (if no user was found with the specified username).
I'm a little late getting in this game, but I've got a question I haven't been able to find the answer to. Your example displays the groups horizontally. Is there a way to display them vertically? I'd like to use this method in displaying a directory and I'd like to go down the columns first, then left to right. And since I'm not a CSS guru either, I thought I'd do it with tables.
I unfortunately ran into a problem while using the code. My Task model has more than one field (name, priority and estimated cost) and they all are required (i.e. there is a validates_presence_of rule for each of them).
The problem happens when the user updates an existing task. More precisely when the user deletes the content of one of the text field and then clicks the remove link for that task.
As you can guess, since the remove links just hides the task, an incomplete task is sent to the controller and since validation happens before the after_callback is called, validation fails, the task is not destroyed and the controller redirects to the update page (with an error saying that the task is invalid)
Fortunately, the solution is not too difficult, all we need is to add a method in the Task class that returns false if the task should be destroyed and the pass that method as an "if" parameter to all validation rules for the task.
@August, @Ryan: then using Model inside the 'authenticate_or_request_with_http_basic' as used on the example, I have support to logout? The authenticate don't will stay registered on client-side?
@Joel: Yeah, that was a stupid question =P It's listed on the "about" page, and is called KeyCastr.
@nelson: As Ryan says, http based authentication doesn't support logout. But as we're rails developers, we should be used to using systems that's opinionated and that makes choices for us - which is exactly what http does. This kind of authentication is rarely used to authenticate users through browsers, but it's ideal for authenticating in API's and so on, as most API reading systems supports the HTTP standards.
I have a really stupid question. What is that Growl type notification that pops up whenever you are executing keyboard shortcuts in Textmate? That could be handy for me if I could figure out what it is and how to get it.
@August, right! Since the authentication is handled in a block there's a lot of flexibility. Moving it to the user model (if you have one) is a good idea.
@nelson, that's a good question. The authentication is kept in the browser (client side), so there's really no way to log out the user on the server side AFAIK. The user will have to close the browser to end the session. I think there are hacks around this issue, but I haven't looked into them.
Oh, hey, that's neat. Was just googling for this. Should make REST-authentication super easy, and then using the usernames and passwords in the database to authenticate.
<pre>
authenticate_or_request_with_httpt_basic do |username, password|
User.authenticate(username, password)
end
</pre>
Hi Ryan,
very nice railscast! This Railcast was very interesting.
A time extended episode about the formating seaction would be great to learn more about layout development (is this so far supported in the writer?).
In general an extend version of PDF:Writer with UTF-8 or international support planned yet?
Could this also be done easily in Ruby (asked from a beginner point of view)?
@James OKelly: and for all who are getting erros like @profile[interest_descriptions] is not allowed as an instance variable name ... it took me half day before I have found out that (probably) the 1.1.6 version I am using behaves differently and can not generate names like project[task_attributes][][text] which are needed here.
Moreover if you bypass fields_for and other helpers altohether it will NOT convert such values to the array within the params hash structure, but forget all but one item. And as the whole method depends strongly on that, you are out of luck. Do the same as me UPGRADE to 1.2.x series. On Debian it means bypasing apt-get and use gem installation of rails.
@ Gernot Kogler: I think that your idea can not work - I have been experimenting quite a lot with it and I think that all duplicate named imputs will get lost (for example if you have twho or more new tasks). The trick of putting the new items to the array only works if there is bare [] in the name of INPUT field. SO I suggest changing your conditional so it gives empty string for new tasks.
I found this railscast series to be particularly useful! After stumbling across Jamis Buck's post about moving associated creations to the model your screen cast really cleared up the concept for me.
Validations had me puzzled, but I finally figured it out. I've posted what worked for me in my situation over on my <a href='http://psifire.livejournal.com/119168.html'>Live Journal</a> page... since I don't have a real blog.
Okay, I understand that. But that still strikes my curiosity. Basically any time an attribute needs to be updated by the user, it can be hacked by a user if they know the column field, or whatever sets it.
So, how would you protect the ability for an admin to make another user an admin or something similar?
If it's in the form that means any user can use the same form and gain those privileges no?
Another example:
Let's say a user has a post, they want to make it either public or private. Since all users have access to that form, what stops them from submitting it to another user_id and another post and changing the privacy level of it? That attribute has to be accessible for it to be set a certain level of privacy.
Is there any rake task or something just to export migration to script in Rails 2.0?
Tnx
A general question about routes:
Is there a naming convention between the route and the model relations?
model:
has_many usercomment
has_many usercomments, :through => usercomment
route:
map.resources :users do |users|
users.resources :usercomments
end
Would this one work?
@Tony
One way to work with pdf is to use the iText java library with a ruby java bridge.
http://blog.codeinmotion.com/index.php/2006/12/22/pdf-generation-in-ruby-on-rails/
@Tony
Just to assure you that you're making the right choice: Indeed.com is showing that there are now more Ruby jobs than there are Cold Fusion jobs:
http://prfsa.com/post.rhtml?title=ruby-passes-coldfusion-at-indeed
ah!! I hit submit and my newsreader lights up, it was just me.
sorry
this didn't show up in my newsreader - am I the only one?
kinda freaked me out a little bit since I'm something of a railscast junkie.
How could I get this to work with middle names?
IOW, give the user the option to enter either an initial, or a full middle name.
My guess is that some Regex might be needed, but perhaps there is a cleaner way
The CSRF protection in Rails 2.0 seems to break this approach, at least for me. When attempting the destroy thru JavaScript, it throws a ActionController::InvalidAuthenticityToken error. Without JS, of course it works.
My main issue with Rails 2.0 is that I don't have any idea how to get my Rails 1.2.x apps to work without disabling CSRF altogether. That seems a little heavy-handed, but I haven't been able to figure out a more elegant solution. Maybe I'm just ignorant of something obvious?
@Chris,
Thank you for the links, they were extremely helpful. Do you have any link about working with database views and ActiveRecord?
Also, can anyone out there answer the PDF question?
Ryan,
You screen casts are the best. I've learned so much from them as I'm attempting to move from ColdFusion to Rails.
There are only two things that are stopping me from making the move and maybe you can shed some light on them and they could be cool ideas for future screen casts.
First - In CF creating a PDF from a webpage is dead easy using the CFDOCUMENT tag. I've watch episode 78 on creating PDFs but it was very clunky at best. Plus you couldn't just pass in a variable containing the HTML to render and have it print out in the PDF. Do you know of any plugin or way to do this?
Second - Database views are never mentioned in any related to rails. Sometimes database views can be invaluable. Take this situation for instance: Suppose you have to get data from two different databases and mash them together. Out of the box ActiveRecord doesn't support multiple databases (though there are plugins that handle this). What you could do however is write a view that grabs the data from both databases and mashes it together.
So my question is: Is there anyway to tell ActiveRecord to create a class file for the view?
[OT]Hello Rayan, did you receive my mail? Because some time my host reject them.
Thanks[/OT]
Is it possible to do something like:
<% my_box do |box| %>
<% box.head do %>
...
<% end %>
<% box.content do %>
...
<% end %>
<% end %>
As you see its going to wrap some HTML for a rounded box.
I tried for several hours to find a solution. The main problem is that i cant capture the contents of the block.call(some_function) method. It always outputs everything to the template immediatly.
Is there a way to it?
"Sexy" is my new least favourite coding buzzword... but good to see the new Rails 2.0 migrations keeping things so damn sexy ;) And the rake tasks which will save me jumping into phpMyAdmin for each new db not to mention the neat generators... as they say: if you have to do something twice - automate it!
wouldn't it be more consequent to write:
script/generate migration add_description_to_tasks description:string -
so tasks instead of task?
(works also) - as we have create_tasks (in plural)...
(same for remove obviously).
Hello,
I just want to say "thank you". I'm new to rails and I like it. Your screencasts are great. I don't understand each of them fully, but from day to day I understand more.
Bye,
Patrick
I would imagine you could still create a session for the user, right?
Also, how would this work for HTTP Digest Authentication? Could you do this with OpenID instead of a Username/Password combination?
Jamal Soueidan
i think liquid is your demand
Hi Ryan.
I use your tip, but my server thow an exception: (part of message)
Missing helper file helpers/all_helper.rb
./script/../config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:71:in `helper'
./script/../config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:58:in `each'
./script/../config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:58:in `helper'
./script/../config/../app/controllers/application.rb:7
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:204:in `load_without_new_constant_marking'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:204:in `load_file'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:343:in `new_constants_in'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:203:in `load_file'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:95:in `require_or_load'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:61:in `depend_on'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:443:in `require_dependency'
./script/../config/../vendor/rails/railties/lib/dispatcher.rb:110:in `prepare_application'
./script/../config/../vendor/rails/railties/lib/dispatcher.rb:39:in `dispatch'
./script/../config/../vendor/rails/railties/lib/webrick_server.rb:113:in `handle_dispatch'
./script/../config/../vendor/rails/railties/lib/webrick_server.rb:79:in `service'
/usr/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
/usr/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
/usr/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
/usr/lib/ruby/1.8/webrick/server.rb:162:in `start'
/usr/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
/usr/lib/ruby/1.8/webrick/server.rb:95:in `start'
/usr/lib/ruby/1.8/webrick/server.rb:92:in `each'
/usr/lib/ruby/1.8/webrick/server.rb:92:in `start'
/usr/lib/ruby/1.8/webrick/server.rb:23:in `start'
/usr/lib/ruby/1.8/webrick/server.rb:82:in `start'
./script/../config/../vendor/rails/railties/lib/webrick_server.rb:63:in `dispatch'
./script/../config/../vendor/rails/railties/lib/commands/servers/webrick.rb:59
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:496:in `require'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:343:in `new_constants_in'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:496:in `require'
./script/../config/../vendor/rails/railties/lib/commands/server.rb:39
./script/server:5:in `require'
./script/server:5
Missing helper file helpers/all_helper.rb
./script/../config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:71:in `helper'
./script/../config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:58:in `each'
./script/../config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:58:in `helper'
./script/../config/../app/controllers/application.rb:7
My helpers:
- html_content_helper
- opcoes_controle_helper
- paginacao_helper
Do you help me?
PS: My Rails version is 1.2.6
I have a patch that avoids the empty {} if you use the index => nil with a select tag at http://dev.rubyonrails.org/ticket/10416
Thanks very much for the episodes and best wishse.
I learned a lot from here.
Hi there, i have managed to implement updating the two models at once and was wondering if it is possible to do three? The third model im using (facilities) habtm the second (room_types). Ideally i would like to be able use check boxes to update the data. Any ideas?
Why create a method on map when you could simply send the actions to the map object?
def controller_paths(controller,*actions)
actions.each do |a|
map.send(#{controller}_#{a},#{controller/a},:controller => controller, :action => a)
end
end
controller_paths :about, :company, :privacy, :liscense
how could i go about reversing the whole thing, so if i had posts from Descember and November, it would show:
December
...
..
November
...
..
October
etc?
@gorn I'm not certain that's the correct solution. I am on a pretty edgy version of Rails (well past 1.2.3) and I am getting this issue as well. Maybe it's the specific version that I am on that is messed up.
Does anyone else have any answers to the dreaded instance variable not found issue?
thanks all.
Excellent...EXCELLENT....*rasps fingers*
@sandro, the "_product.html.erb" partial only contains the html to display the product - not any form/fields to edit a product. I did not put form fields in a partial for simplicity sake, but you would likely want to create some kind of "_form.html.erb" partial for that.
@mikem, I have a test helper method which does the login process. I just call that at the beginning of any test which needs to login.
This login method can do several things. One is to mock the @controller.current_user method to return an account of your choosing. Another is to load a fixture record if you're using that.
How do you deal with testing actions that require logged in user ? Is there a new way for doing this ?
@August Lilleaas
You are absolutely right. To elaborate a bit more for nelson jr, with HTTP Basic Authentication and REST you won't need to use a server-side session at all. The server authenticates you and services your request. You then cease to exist to the server, as you are not actually "logged in".
This makes running a service/site across a cluster or servers simple because your session state (logged in, not logged in etc) isn't of any concern. A subsequent request could go to any server in a cluster and it wouldn't be a problem because you provide your authentication details again.
This is a very handy little tip, thanks. Keep up the good work with the casts too.
Just one question: How would you go about producing a list of the months so that every month of the year was listed whether it has anything to group under it or not? (Does that make sense?!?!)
Cheers
@nelson jr: As opposed to the "normal" way of authenticating, where you set session[:user] to something (which is what e.g. the restful_authentication does), this particular method authenticates you if the stuff inside the block returns true. So, doing this would authenticate you:
authenticate_or_request_with_http_basic { true }
This is what a User.authenticate action could look like:
def self.authenticate(username, password)
user = self.find_by_username(username)
user && user.valid_password?(password)
end
This method returns true if a user was found and the password was valid. Otherwise, it returns false (if the password wasn't valid) or nil (if no user was found with the specified username).
+1 for Pascal's suggestion
habtm would rock for this
I'm a little late getting in this game, but I've got a question I haven't been able to find the answer to. Your example displays the groups horizontally. Is there a way to display them vertically? I'd like to use this method in displaying a directory and I'd like to go down the columns first, then left to right. And since I'm not a CSS guru either, I thought I'd do it with tables.
Thanks.
Ryan,
would it be possible to have an RSS feed for tracking the comments for each episode?
In some cases, the comments/questions and answers are quite interesting too.
Thanks again for the great work
Ryan,
great tutorial.
I unfortunately ran into a problem while using the code. My Task model has more than one field (name, priority and estimated cost) and they all are required (i.e. there is a validates_presence_of rule for each of them).
The problem happens when the user updates an existing task. More precisely when the user deletes the content of one of the text field and then clicks the remove link for that task.
As you can guess, since the remove links just hides the task, an incomplete task is sent to the controller and since validation happens before the after_callback is called, validation fails, the task is not destroyed and the controller redirects to the update page (with an error saying that the task is invalid)
Fortunately, the solution is not too difficult, all we need is to add a method in the Task class that returns false if the task should be destroyed and the pass that method as an "if" parameter to all validation rules for the task.
def do_validation
!should_destroy?
end
validates_presence_of :name, :priority, :estimated_cost, :if => :do_validation
@August, @Ryan: then using Model inside the 'authenticate_or_request_with_http_basic' as used on the example, I have support to logout? The authenticate don't will stay registered on client-side?
(srry my english guys)
[]s :)
@Joel: Yeah, that was a stupid question =P It's listed on the "about" page, and is called KeyCastr.
@nelson: As Ryan says, http based authentication doesn't support logout. But as we're rails developers, we should be used to using systems that's opinionated and that makes choices for us - which is exactly what http does. This kind of authentication is rarely used to authenticate users through browsers, but it's ideal for authenticating in API's and so on, as most API reading systems supports the HTTP standards.
I have a really stupid question. What is that Growl type notification that pops up whenever you are executing keyboard shortcuts in Textmate? That could be handy for me if I could figure out what it is and how to get it.
@August, right! Since the authentication is handled in a block there's a lot of flexibility. Moving it to the user model (if you have one) is a good idea.
@nelson, that's a good question. The authentication is kept in the browser (client side), so there's really no way to log out the user on the server side AFAIK. The user will have to close the browser to end the session. I think there are hacks around this issue, but I haven't looked into them.
@Paul: Do some investigation work on mocking and stubbing. It's wonderful.
I'm a little confused. If you use
<!-- index.html.erb -->
<%= render :partial => @products %>
<!-- show.html.erb -->
<%= render :partial => @product %>
does it means the the _product.html.erb partial contains the fields of the forms (edit/new) and also the lines of your list (index).
What am I missing here?
Hi. Sorry my stupid question, but how can I do logout using http_basic? :-)
Bye
Oh, hey, that's neat. Was just googling for this. Should make REST-authentication super easy, and then using the usernames and passwords in the database to authenticate.
<pre>
authenticate_or_request_with_httpt_basic do |username, password|
User.authenticate(username, password)
end
</pre>
Wohoo!
Hi Ryan,
very nice railscast! This Railcast was very interesting.
A time extended episode about the formating seaction would be great to learn more about layout development (is this so far supported in the writer?).
In general an extend version of PDF:Writer with UTF-8 or international support planned yet?
Could this also be done easily in Ruby (asked from a beginner point of view)?
Thanks for the video Ryan, very useful.
And how do you test without "external" data?
@James OKelly: and for all who are getting erros like @profile[interest_descriptions] is not allowed as an instance variable name ... it took me half day before I have found out that (probably) the 1.1.6 version I am using behaves differently and can not generate names like project[task_attributes][][text] which are needed here.
Moreover if you bypass fields_for and other helpers altohether it will NOT convert such values to the array within the params hash structure, but forget all but one item. And as the whole method depends strongly on that, you are out of luck. Do the same as me UPGRADE to 1.2.x series. On Debian it means bypasing apt-get and use gem installation of rails.
Hope it will same half day to others :-)
@ Gernot Kogler: I think that your idea can not work - I have been experimenting quite a lot with it and I think that all duplicate named imputs will get lost (for example if you have twho or more new tasks). The trick of putting the new items to the array only works if there is bare [] in the name of INPUT field. SO I suggest changing your conditional so it gives empty string for new tasks.
I found this railscast series to be particularly useful! After stumbling across Jamis Buck's post about moving associated creations to the model your screen cast really cleared up the concept for me.
Validations had me puzzled, but I finally figured it out. I've posted what worked for me in my situation over on my <a href='http://psifire.livejournal.com/119168.html'>Live Journal</a> page... since I don't have a real blog.
@Daniel,
To make an attribute only settable by admins you can do this:
@user.admin = params[:user][:admin] if current_user.admin?
This way the admin parameter for the user will only be set if the current user is an admin. Does that answer your question?
@Ryan
@user.admin = true
Okay, I understand that. But that still strikes my curiosity. Basically any time an attribute needs to be updated by the user, it can be hacked by a user if they know the column field, or whatever sets it.
So, how would you protect the ability for an admin to make another user an admin or something similar?
If it's in the form that means any user can use the same form and gain those privileges no?
Another example:
Let's say a user has a post, they want to make it either public or private. Since all users have access to that form, what stops them from submitting it to another user_id and another post and changing the privacy level of it? That attribute has to be accessible for it to be set a certain level of privacy.