Wish I had found this a couple of months ago, it would have moved me along a lot. I still learned a good deal from it though.
Check it out at:
Rails Envy
-Ralph
Wish I had found this a couple of months ago, it would have moved me along a lot. I still learned a good deal from it though.
Check it out at:
Apparently Rails typecasts MySQL tinyint's as booleans. I was working on a Rails app for a legacy database today when I realized that I couldn't pull the value out of my 'terms' column. All it would read is a true or false, and not the actual value. After a bit of research, I discovered before_type_cast accessor. So instead of using report.terms, in order to get the value out, I had to use report.terms_before_type_cast.
Short post, but I'm sure someone will have the same problem at some point and will find it helpful.
Today, I'm going to go over a quick tutorial of some basic AJAX functions. Rails has a great implementation with AJAX right out of the box, with the Prototype library. It also includes the Scriptaculous library with some special effects. We are just going to do some basic writing text into the site without page reloading. Lets get started.
rails ajaxtest -d mysql
cd ajaxtest
./script/generate model Foobar foo:string bar:string
./script/generate Controller Foobars
This is our first project that doesn't use scaffolding - I decided against it because scaffolding would have generated all kinds of views we aren't going to need for this. Notice that when you created the model, it automatically generated your DB migration file. Now, lets open up app/controllers/foobars_controller.rb and do this:
class FoobarsController < ApplicationController
def index
@foobars = Foobar.find(:all)
respond_to do |format|
format.html # index.html.erb
end
end
end
Next, create app/views/foobars/index.html.erb:
<h3>Foobars!</h3>
<table>
<tr><th>Foo</th><th>Bar</th></tr>
<% for foobar in @foobars do %>
<tr>
<td><%= foobar.foo %></td>
<td><%= foobar.bar %></td>
</tr>
<% end %>
</table>
Now lets add our routing. In config/routes.rb add:
map.resources :foobars
In your console, lets get our db created and foobars table setup:
rake db:create
rake db:migrate
And one last thing. We need to populate our table with a few foobars. This is a good time to show you the rails interactive console:
./script/console
From here, we can give commands directly to our project. Lets try one:
Foobar.find(:all)
>> Foobar.find(:all)
=> []
So it returned an empty array. The interactive console is great for playing around with bits of code to see what they do or even testing out bits of code. Lets try another command:
>> myfoobar = Foobar.new
=> #<Foobar id: nil, foo: nil, bar: nil, created_at: nil, updated_at: nil>
>>
Creates a new foobar object...
>> myfoobar.foo = "This is a test."
=> "This is a test."
>> myfoobar.bar = "This is only a test."
=> "This is only a test."
>>
We can set the values of foo and bar for our new foobar, and...
>> myfoobar.save
=> true
>>
We can save it to the database. Lets try looking it up with find...
>> Foobar.find(:all)
=> [#<Foobar id: 1, foo: "This is a test.", bar: "This is only a test.", created_at: "2008-03-21 18:24:46", updated_at: "2008-03-21 18:24:46">]
>>
Great - so far so good. Now lets create a few more foobars:
myfoobar = Foobar.new
myfoobar.foo = "Foo of foobar #2"
myfoobar.bar = "Bar of foobar #2"
myfoobar.save
myfoobar = Foobar.new
myfoobar.foo = "Foo of foobar #3"
myfoobar.bar = "Bar of foobar #3"
myfoobar.save
myfoobar = Foobar.new
myfoobar.foo = "Foo of foobar #4"
myfoobar.bar = "Bar of foobar #4"
myfoobar.save
And done. You can type exit to leave the interactive console. Start the server, browse to localhost:PORT/foobars
First thing, I'm going to tell you that if you don't have Firebug yet, go ahead and get it. It is a plugin for Firefox(you are using firefox, right? nothing against you Safari/Opera lovers..if you are using IE you have no excuses, get Firefox and get Firebug...now). Firebug is a great tool for design as well as for AJAX. The inspect mode will highlight divs under your mouse and show the corresponding html/css code in the panel below. You can also take a look at Javascript AJAX responses and more quickly debug your code. Lets create app/views/layouts/application.html.erb:
<html>
<head>
<%= javascript_include_tag :defaults %>
</head>
<body>
<%= yield :layout %>
</body>
</html>
The include tag will include (among other things) the prototype library that you need to make the AJAX calls. Now, lets head back to app/views/foobars/index.html.erb and set it up for our AJAX. Change it to this:
<h3>Foobars!</h3>
<table>
<tr>
<th>Foo</th>
<th>Bar</th>
<th>Which?</th>
<th>Links</th>
</tr>
<% for foobar in @foobars do %>
<% idstring = "foobar-" + foobar.id.to_s %>
<tr>
<td><%= foobar.foo %></td>
<td><%= foobar.bar %></td>
<td id="<%= idstring %>"></td>
<td>
<%= link_to_remote "Foo", :url =>{ :action => :set, :updatewith => foobar.foo },
:update => idstring %>
<%= link_to_remote "Bar", :url =>{ :action => :set, :updatewith => foobar.bar },
:update => idstring %>
</td>
</tr>
<% end %>
</table>
We have 2 more columns in our table now - Which? will be updated by AJAX with either the foo or the bar of our current Foobar depending on the link clicked from the Links column. In the Links column, we have 2 link_to_remote 's. link_to_remote generates all the javascript calls to send an AJAX request back to our controller on the server. The first argument is what will be displayed for the link. In :url, we define the action to send the request to (:set), as well as the string we want to pass into the function (:updatewith). Last, :update will be the name of the div we will be updating. You can also add another parameter, :position. For example, :position => :before would insert whatever you are sending before the td tag, :after would be after it, :top would insert it inside the td, above anything else, and :bottom inserts it inside the td, at the bottom. If you do not specify a position(like we are doing), it will simply over-write what is inside the div. One more thing to do; lets open up app/controllers/foobars_controller.rb and add in our :set action:
def set
render :text => params[:updatewith]
end
Go back to the page and try clicking the links
Update: I found this link to be very helpful with different ways of using render with AJAX.
And we are done! Thanks for visiting, and see you next time.
So I'm using ActiveScaffold to create an admin interface for a site, using a legacy database. It has a table called 'Events', one of the column names is event, of type medium blob, which will only contain text. ActiveScaffold will display the contents of the blob field correctly, but when you go to create a new Event or edit an existing one, it will not give you a text field to enter anything in. Here is the fix:
In app/helpers, I created a file event_helper.rb and put this code in it:
module EventHelper
def event_form_column(record, input_name)
text_field :record, :event, :name => input_name
end
end
And everything worked fine.
So today I was working on a project. This project will be an admin interface for an application that has already been running for a while(which was written in PHP). So I am having to use a legacy database(tutorial coming soon for making admin interface for a legacy DB!) Anyway, I have an employee, and a department. The employee references which department he is in by the ID. However, some employees have an ID that is not used in the department table(department got deleted at some point, never existed, who knows?).
Here is what I tried first:
def deptname
dept = Department.find(thisdept)
dept.name
end
ActiveRecord::RecordNotFound in Employees#index
Showing vendor/plugins/active_scaffold/frontends/default/views/_list_record.rhtml where line #10 raised:
Couldn't find Department with ID=13
So we are going to need something along the lines of a try - catch. Ruby's equivalent is the begin-rescue-else-end. Begin is the code that might throw an error. Rescue is the code to excute if there is an error. Else is executed if there is no error. You can also add an ensure block, which will be run after everything, regardless. Here is my fix:
def deptname
begin
dept = Department.find(thisdept)
rescue
"No Department"
else
dept.name
end
end
Works like a charm! See you next time.
cd myforum
ruby script/plugin install http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk
ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication
ruby script/generate authenticated user sessions --include-activation --stateful
To break down that last command - authenticated is part of the restful_authentication. user is the model to be generated for the user. sessions will be the controller to handle logging in/out, --include-activation will help with creating the stuff needed to mail an activation link to the user's email, and --stateful is for support for acts_as_state_machine plugin.
Now that our files are generated, let's head to /config/routes.rb and make a couple of changes. Notice that the map.resources :users and map.resources :session lines have already been generated by the generate authenticated call. The version of restful_authentication used in the tutorial on RubyPlus did not automatically generate them.
So in routes.rb:
#CHANGE THIS LINE
map.resources :users
#TO THIS
map.resources :users, :member => { :suspend => :put,
:unsuspend => :put,
:purge => :delete }
#AND THEN ADD THE FOLLOWING LINES
map.activate '/activate/:activation_code', :controller => 'users',
:action => 'activate'
map.signup '/signup', :controller => 'users', :action => 'new'
map.login '/login', :controller => 'sessions', :action => 'new'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.forgot_password '/forgot_password', :controller => 'users',
:action => 'forgot_password'
map.reset_password '/reset_password/:id', :controller => 'users',
:action => 'reset_password'
The :member => part sets up some restful actions for the users controller. All the lines that we added sets up named routes for user and session controller/action pairs.
Now, open up /config/environment.rb:
#BELOW THE LINE
Rails::Initializer.run do |config|
#ADD THIS
config.active_record.observers = :user_observer
The observer watches the user model and will be used to send an EMail whenever a new user is created. Next, lets open up /db/migrate/004_create_users.rb and do this.
#OLD 004_create_users.rb
class CreateUsers < ActiveRecord::Migration
def self.up
create_table "users", :force => true do |t|
t.column :login, :string
t.column :email, :string
t.column :crypted_password, :string, :limit => 40
t.column :salt, :string, :limit => 40
t.column :created_at, :datetime
t.column :updated_at, :datetime
t.column :remember_token, :string
t.column :remember_token_expires_at, :datetime
t.column :activation_code, :string, :limit => 40
t.column :activated_at, :datetime
t.column :state, :string, :null => :no, :default => 'passive'
t.column :deleted_at, :datetime
end
end
def self.down
drop_table "users"
end
end
#NEW 004_create_users.rb
class CreateUsers < ActiveRecord::Migration
def self.up
create_table "users", :force => true do |t|
t.string :login, :email, :remember_token
t.string :crypted_password, :limit => 40
t.string :password_reset_code, :limit => 40
t.string :salt, :limit => 40
t.string :activation_code, :limit => 40
t.datetime :remember_token_expires_at, :activated_at, :deleted_at
t.string :state, :null => :no, :default => 'passive'
t.timestamps
end
end
def self.down
drop_table "users"
end
end
There we are just cleaning up the code a little bit. We did add a :password_reset_code column - will be used if a user forgets their password(more on that later). Now just run the migration to create our new tables...
rake db:migrate
Next, open up app/controllers/sessions_controller and copy the line include AuthenticatedSystem to /app/controllers/application.rb. Also, in users_controller, remove the same line. This will make sure that the restful_authentication functions are included on every page.
Now, remove these lines from users_controller in the create function:
self.current_user = @user
redirect_back_or_default('/')
We removed the first line because we do not want to log the user in when they register, we want to verify their EMail. The second line was removed so that Rails would look for create.html.erb after running the create action. Now, create a file /app/views/users/create.html.erb and put something like this in it:
<fieldset>
<legend>Your forum account</legend>
<p>
An EMail has been sent to <%= @user.email %> with instructions to activate
your account.
<li>
If your email is not valid, you must <%= link_to "signup", signup_path %>
again and provide a valid email address.
</li>
<li>
If you don't recieve an email, check your bulk or trash folder, as your spam
filter may have inadvertantly caught the registration email.
</li>
</p>
</fieldset>
Also, create the files app/views/users/change_password.html.erb, app/views/users/forgot_password.html.erb, app/views/users/reset_password.html.erb:
#change_password.html.erb
<% form_for :action => 'change_password' do |f| %>
<fieldset>
<dl>
<dt><label for="old_password" class="block">Old Password</label></dt>
<dd><%= password_field_tag 'old_password', @old_password, :size => 45, :class => 'text' %></dd>
<dt><label for="password" class="block">New Password</label></dt>
<dd><%= password_field_tag 'password', {}, :size => 45, :class => 'text' %>
<div><small>Between 4 and 40 characters</small></div></dd>
<dt><label for="password_confirmation" class="block">Confirm new password</label></dt>
<dd><%= password_field_tag 'password_confirmation', {}, :size => 45, :class => 'text' %></dd>
</dl>
<%= submit_tag 'Change password' %>
</fieldset>
<%end%>
#forgot_password.html.erb
<% form_for :user, :url => {:action => 'forgot_password'} do |form| %>
<fieldset>
<legend>Password Reset Request</legend>
<p>Enter your email address that we have on our file and click send. We will send you a
password reset link email to your email address.</p>
<p>
<label for="user_email" >Email Address:</label><br/>
<%= form.text_field :email, :size => 35, :class => 'text' %>
</p>
<%= submit_tag 'Send' %>
</fieldset>
<% end %>
#reset_password.html.erb
<% form_for :user, :url => {:action => "reset_password"} do |form| %>
<fieldset>
<legend>Reset Password</legend>
<p>
<label for="user_password" >Password</label><br/>
<%= form.password_field :password, :size => 45, :class => 'text' %>
</p>
<p>
<label for="user_password_confirmation" >Confirm Password</label><br/>
<%= form.password_field :password_confirmation, :size => 45, :class => 'text' %>
</p>
<%= submit_tag "Reset your password" %>
</fieldset>
<% end %>
</pre>
<p>Standard stuff there.</p>
<p>Now, open up app/helpers/application_helper.rb and add this code:</p>
<pre>
def user_logged_in?
session[:user_id]
end
We can use this in our views to see if the user is logged in.
Create app/views/layouts/application.html.erb:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-US">
<head>
<title><%= @page_title || 'Rails 2.0 Forum' %></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<%= stylesheet_link_tag 'style' %>
<%= javascript_include_tag :defaults %>
</head>
<body>
<!-- ##### Header ##### -->
<div id="header">
<div class="superHeader">
<% if user_logged_in? %>
<span>You are logged in as: </span>
<%= current_user.login %>
<% else %>
<span>Welcome Guest</span>
<% end %>
</div>
<div class="midHeader">
<h1 class="headerTitle" lang="la">Rails 2.0 Forum</h1>
</div>
<div class="subHeader">
<span class="doNotDisplay">Navigation:</span>
<% if user_logged_in? %>
<%= link_to 'Logout', logout_url %>
<% else %>
<%= link_to "Signup", signup_url %>
| <%= link_to 'Login', login_url %>
<% end %>
| <%= link_to 'Contact Us', 'contact' %>
</div>
</div>
<!-- ##### Main Copy ##### -->
<div id="main-copy">
<% flash.each do |key,value| %>
<div id="flash" class="flash_<%= key %>" >
<span class="message"><%= value %></span>
</div>
<% end -%>
<%= yield :layout %>
</div>
</body>
</html>
And then delete forums.html.erb, replies.html.erb, and topics.html.erb so that only the application.html.erb will show.
Lets go ahead and get some different styling in this. Download this stylesheet and toss it in /public/stylesheets.
Alright! Now we should be able to fire up the server and have a look at what we've got.
Next, open up app/views/sessions/new.html.erb. Uncomment the 'Remember me' section, and then next to the submit button, add:
<%= link_to 'Forgot Password?', forgot_password_url %>
Create /app/views/users/change_password.html.erb:
<% form_for :action => 'change_password' do |f| %>
<fieldset>
<dl>
<dt><label for="old_password" class="block">Old Password</label></dt>
<dd><%= password_field_tag 'old_password', @old_password, :size => 45,
:class => 'text' %></dd>
<dt><label for="password" class="block">New Password</label></dt>
<dd><%= password_field_tag 'password', {}, :size => 45, :class => 'text' %>
<div><small>Between 4 and 40 characters</small></div></dd>
<dt><label for="password_confirmation" class="block">
Confirm new password</label></dt>
<dd><%= password_field_tag 'password_confirmation', {}, :size => 45,
:class => 'text' %></dd>
</dl>
<%= submit_tag 'Change password' %>
</fieldset>
<%end%>
Create /app/views/users/forgot_password.html.erb
<% form_for :user, :url => {:action => 'forgot_password'} do |form| %>
<fieldset>
<legend>Password Reset Request</legend>
<p>Enter your email address that we have on our file and click send. We will
send you a password reset link email to your email address.</p>
<p>
<label for="user_email" >Email Address:</label><br/>
<%= form.text_field :email, :size => 35, :class => 'text' %>
</p>
<%= submit_tag 'Send' %>
</fieldset>
<% end %>
And create /app/views/users/reset_password.html.erb
<% form_for :user, :url => {:action => "reset_password"} do |form| %>
<fieldset>
<legend>Reset Password</legend>
<p>
<label for="user_password" >Password</label><br/>
<%= form.password_field :password, :size => 45, :class => 'text' %>
</p>
<p>
<label for="user_password_confirmation" >Confirm Password</label><br/>
<%= form.password_field :password_confirmation, :size => 45, :class => 'text' %>
</p>
<%= submit_tag "Reset your password" %>
</fieldset>
<% end %>
We are moving kind of fast here, but most of this stuff should make sense to you, you just need to see it in action. If you have any questions over how anything works, leave a comment and I will get back to you.
Now, in app/controllers/users_controller.rb, lets add in the actions for forgot_password, reset_password, and change_password:
def change_password
return unless request.post?
if User.authenticate(current_user.login, params[:old_password])
if ((params[:password] == params[:password_confirmation]) &&
!params[:password_confirmation].blank?)
current_user.password_confirmation = params[:password_confirmation]
current_user.password = params[:password]
if current_user.save
flash[:notice] = "Password successfully updated"
redirect_to profile_url(current_user.login)
else
flash[:alert] = "Password not changed"
end
else
flash[:alert] = "New Password mismatch"
@old_password = params[:old_password]
end
else
flash[:alert] = "Old password incorrect"
end
end
#gain email address
def forgot_password
return unless request.post?
if @user = User.find_by_email(params[:user][:email])
@user.forgot_password
@user.save
redirect_back_or_default('/')
flash[:notice] = "A password reset link has been sent to your email address"
else
flash[:alert] = "Could not find a user with that email address"
end
end
#reset password
def reset_password
@user = User.find_by_password_reset_code(params[:id])
return if @user unless params[:user]
if ((params[:user][:password] && params[:user][:password_confirmation]) &&
!params[:user][:password_confirmation].blank?)
self.current_user = @user #for the next two lines to work
current_user.password_confirmation = params[:user][:password_confirmation]
current_user.password = params[:user][:password]
@user.reset_password
flash[:notice] = current_user.save ? "Password reset success." : "Password reset failed."
redirect_back_or_default('/')
else
flash[:alert] = "Password mismatch"
end
end
In config/environments/development.rb you need to add SITE="http://localhost:3000" at the bottom, we will get to this in just a sec.
Now we will take a look at the user_mailer views. They are used to format emails sent out to users. In app/views/user_mailer/activation.html.erb, remove the part where it says "You may now start adding your plugins:". Now lets create app/views/user_mailer/forgot_password.html.erb, and app/views/user_mailer/reset_password.html.erb:
#forgot_password.html.erb
Dear <%= @user.login %>,
We have had a request to reset your password, please visit
<%= @url %>
#reset_password.html.erb
Your have reset the password for your account successfully.
Username: <%= @user.login %>
Password: <%= @user.password %>
Now lets edit app/models/user.rb. Near the bottom, somewhere after the protected keyword, add the follow function:
def make_password_reset_code
self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
end
And then above protected, add these functions:
def forgot_password
@forgotten_password = true
self.make_password_reset_code
end
def reset_password
# First update the password_reset_code before setting the
# reset_password flag to avoid duplicate email notifications.
update_attributes(:password_reset_code => nil)
@reset_password = true
end
#used in user_observer
def recently_forgot_password?
@forgotten_password
end
def recently_reset_password?
@reset_password
end
def recently_activated?
@recent_active
end
And now we need to set up the user_mailer model to use all of this. Change app/models/user_mailer.rb to look like this:
class UserMailer < ActionMailer::Base
def signup_notification(user)
setup_email(user)
@subject += 'Please activate your new account'
@body[:url] = "#{SITE}/activate/#{user.activation_code}"
end
def activation(user)
setup_email(user)
@subject += 'Your account has been activated!'
@body[:url] = "#{SITE}/"
end
def forgot_password(user)
setup_email(user)
@subject += 'You have requested to change your password'
@body[:url] = "#{SITE}/reset_password/#{user.password_reset_code}"
end
def reset_password(user)
setup_email(user)
@subject += 'Your password has been reset.'
end
protected
def setup_email(user)
recipients "#{user.email}"
from %("Rails Forum Admin") # Sets the User FROM Name and Email
subject "[Rails Forum] New account information "
body :user => user
sent_on Time.now
end
end
Note where we used the SITE constant that we set in development.rb earlier. Lets stop the server and then restart it since we changed the development.rb. Now, we should be able to go back and sign up.
If you check the console running your server, you will see SQL queries adding the new user to the database, and the email being sent(it won't actually send an email since we are in development)
Go to think link from the console(localhost:3000/activate/whatever) and you will get a message saying 'Signup complete' and you will be logged in. It will also send an email saying that your account has been activated. You can test everything by logging out and logging back in again.
Alright, we are almost done! Next, open up app/models/user_observer.rb and change the after_save function to this:
def after_save(user)
UserMailer.deliver_activation(user) if user.recently_activated?
UserMailer.deliver_forgot_password(user) if user.recently_forgot_password?
UserMailer.deliver_reset_password(user) if user.recently_reset_password?
end
Just more setting up for the mailer.
So, now we have a Signup, a few ways for taking care of forgotten passwords, and email authentication. But how do we block the adding posts and replies to only people logged in? How do we restrict creating forums and deleting posts to only an admin? Open up the file vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_system.rb and read through some of the comments about the functions:
# Returns true or false if the <%= file_name %> is logged in.
# Preloads @current_<%= file_name %> with the <%= file_name %> model if they're logged in.
def logged_in?
current_<%= file_name %> != :false
end
# Accesses the current <%= file_name %> from the session. Set it to :false if login fails
# so that future calls do not hit the database.
def current_<%= file_name %>
@current_<%= file_name %> ||= (login_from_session || login_from_basic_auth || login_from_cookie || :false)
end
logged_in? checks the value of current_user and returns true if it does not equal :false. current_user tries to login from a session, from basic auth, and from a cookie. If it is unable to log them in, it will return :false and cause the value of logged_in to be false.
# Check if the <%= file_name %> is authorized
#
# Override this method in your controllers if you want to restrict access
# to only a few actions or if you want to check if the <%= file_name %>
# has the correct rights.
#
# Example:
#
# # only allow nonbobs
# def authorized?
# current_<%= file_name %>.login != "bob"
# end
def authorized?
logged_in?
end
# Filter method to enforce a login requirement.
#
# To require logins for all actions, use this in your controllers:
#
# before_filter :login_required
#
# To require logins for specific actions, use this in your controllers:
#
# before_filter :login_required, :only => [ :edit, :update ]
#
# To skip this in a subclassed controller:
#
# skip_before_filter :login_required
#
def login_required
authorized? || access_denied
end
We can use before_filter :login_required to stop people from going to /topic/1/posts/2/edit and being able to edit the post. logged_in? can be used in forum and topic's show views, to stop the form for new topics and replies from being shown. This can all be setup however you want, there are plenty of possibilities. What I am going to do is show you how to display different things based on who is logged in, and how to limit certain actions in your controllers. That should give you enough to figure out what you want to do for your specific application. First, open up app/views/forums/show.html.erb:
#find these 3 lines
<h2>New Post</h2>
<%= render :partial => @topic = Topic.new, :locals => { :button_name => 'Create' } %>
<%= link_to 'New Topic', new_forum_topic_path(@forum) %> |
#and put this around them
<% if logged_in? %>
<h2>New Post</h2>
<%= render :partial => @topic = Topic.new, :locals => { :button_name => 'Create' } %>
<%= link_to 'New Topic', new_forum_topic_path(@forum) %> |
<%end>
#and then change this line
<%= link_to 'Edit', edit_forum_path(@forum) %> |
#to this
<% if is_admin? %>
<%= link_to 'Edit', edit_forum_path(@forum) %> |
<% end %>
And now, go to app/controllers/application.rb. In this file we can write functions that will be available to all controllers. Add this to it:
helper_method :is_admin?
def is_admin?
if logged_in? && current_user.login == "admin"
true
else
false
end
end
def admin_required
is_admin? || admin_denied
end
def admin_denied
respond_to do |format|
format.html do
store_location
flash[:notice] = 'You must be an admin to do that.'
redirect_to forums_path
end
end
end
The first line, helper_method :is_admin? will let this function be used in the view. current_user.login is the username for the person logged in. You can change this method however you want to determine whether or not a user is an admin. admin_required and admin_denied will be used in our controllers to restrict access to actions - lets go to our app/controllers/forums_controller.rb and put that in:
#at the very top, right after class ForumsController < ApplicationController, add this line:
before_filter :admin_required, :only => [ :edit, :update, :create, :new, :destroy ]
Now, when you try to access edit, update, create, new, or destroy actions in your controller, if your username is not 'admin', it will go to the show forums page and have a flash saying 'You must be an admin to do that'.
Well, I guess that is it for now. We've added the ability to create users, reset passwords, verify email, and restrict actions to admins. This isn't a completely finished web app. We didn't look into any kind of input validation and we didn't go over all the things we would need to limit to users logged in(create post and create reply), and we didn't limit a lot of things to admins that we should have(such as editing and destroying posts/replies). Hopefully, you've learned enough from this to be able to figure it out yourself, but if you have any trouble feel free to leave a comment. Also, let me know if there are any typos, mistakes, or questions about the tutorial, as well if you have any suggestions. Thanks for reading!
-Ralph