I was following the tutorial at http://www.logansbailey.com/ and modified it to enable an unregistered person to be able to register with a username, email and password.
I already enabled a logged in user to modify his/her email and password but not the username.
What I want to add is:
1) to enable a logged in user to be able to see/reach his/her username and email,
2) to enable a user with admin_flag set (I handled this in the sql table and created the user) to be able to see/modify all user records.
I modifyed the app/cotrollers/user_controller.rb like this:
class UsersController < ApplicationController
before_filter :is_user, :only => [:index, :show, :edit, :update, :destroy]
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user }
end
end
def edit
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'Registration successful.'
format.html { redirect_to(:controller => 'home', :action => 'tutorial') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #user.update_attributes(params[:user])
flash[:notice] = 'Your profile was successfully updated.'
format.html { redirect_to(:controller => 'home', :action => 'index') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
def is_user
if User.exists?(params[:id])
#user = User.find(params[:id]);
if current_user.admin_flag == true
flash[:notice] = 'Welcome Admin'
end
if !current_user || current_user.id != #user.id
flash[:notice] = 'You do not have access to that page'
redirect_to(:controller => 'home', :action => 'index')
end
else
flash[:notice] = 'You do not have access to that page'
redirect_to(:controller => 'home', :action => 'index')
end
end
end
The file app/models/user.rb is:
class User < ActiveRecord::Base
acts_as_authentic
end
And I can confirm that the admin_flag set user is get correctly since the file app/views/layouts/application.html.erb containing:
<div id="admin">
<% if current_user %>
<% if current_user.admin_flag == true %> |
<%= link_to "Users", users_path %>
<% end %>
<% end %>
</div>
correctly displays the 'Users' link when I log in as the admin.
Now the problem is that I can't get the show all users, edit other users etc.. functionality. As the admin, I can show and modify the admin user just like all the other ordinary users, meaning I can't modify the username, too.
What may be wrong here?
When you added a boolean attribute admin to user in the right way, the Rails should add question-mark method admin? in User model. It's not important but for convenience.
On every method you want to protect from unwanted actions use before_filter:
class UsersController < ApplicationController
before_filter :admin_user, :only => :destroy
before_filter :correct_user, :only => [:edit, :update]
def destroy
end
...
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user) || current_user.admin?
end
end
In views more convenient to use current_user.admin?
<div id="admin">
<% if current_user.admin? %>
<%= link_to "Users", users_path %>
<% end %>
</div>
Related
I have the following that update user profile. It does perfectly fine with base url (http://domain_name.com/users/).
def update
#user = User.find(params[:id])
respond_with #user do |format|
if #user.update_attributes(params[:user])
if current_user.becomes(User) == #user
sign_in(#user, :bypass => true)
end
flash[:notice] = 'User was successfully updated.'
format.html { redirect_to #user }
format.json { render :status => :ok }
else
format.html { render :action => 'edit' }
format.json { render :status => :bad_request }
end
end
end
Now I want to move it into admin namespace (http://domain_name.com/admin/users/). And what I try is to change
redirect_to #user
to
redirect_to admin_user_path(#user)
then I got:
def update
#user = User.find(params[:id])
#respond_with(#user) do |format|
respond_with(#user, :location => admin_user_path(#user)) do |format|
if #user.update_attributes(params[:user])
if current_user.becomes(User) == #user
sign_in(#user, :bypass => true)
end
flash[:notice] = 'User was successfully updated.'
format.html { redirect_to admin_user_path(#user) }
format.json { render :status => :ok }
else
format.html { render :action => 'edit', :location => edit_admin_path(user) }
format.json { render :status => :bad_request }
end
end
end
But it does not work. I also try to change
respond_with(#user) do |format|
to something like
respond_with(#user, :location => admin_user_path(#user)) do |format|
But it doesn't work too. Can anyone have some experience, please give me some advice or explanation.
Thanks!
I do believe the following line:
respond_with(#user, :location => admin_user_path(#user)) do |format|
Seems a bit odd to me. I would've thought this should be respond_with(#user) do |format|
Also take a read of the following: Ryan's Scraps - Cleaner RESTful Controllers / respond_with. Ryan states the following under Pre-Action Overriding:
It’s also possible to override standard resource handling by passing in a block to respond_with specifying which formats to override for that action.
From this you will see that the formats that are to be overrided are declared at the top of the class using respond_to
On a page I have task listed out. I want to put a form for that task as an update to complete that task. I have the following code as a form_for:
<%= form_for :event, :action => :update, :id => event.id do |f| %>
<%= f.check_box :complete %>
<%= f.submit 'Complete %>
<% end %>
With this code I want it to edit the event with the id in the url and complete the event. What it does it creates a new event instead. Any ideas?
Event Controller:
class EventsController < ApplicationController
layout 'events', :except => 'edit'
# GET /events
# GET /events.json
def index
#events = Event.order("events.initials ASC, events.priroty ASC")
#archived = CompleteEvent.order("complete_events.created_at ASC")
respond_to do |format|
format.html # index.html.erb
format.json { render json: #events }
end
end
# GET /events/1
# GET /events/1.json
def show
#event = Event.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #event }
end
end
# GET /events/new
# GET /events/new.json
def new
#event = Event.new
#users = ['BG', 'BD', 'MB', 'AF', 'RA', 'JM']
#name = ['Brad Garrison', 'Brian Davis', 'Matt Broach', 'Alan McFarland', 'Russell Anderson', 'Jason Milam']
respond_to do |format|
format.html # new.html.erb
format.json { render json: #event }
end
end
# GET /events/1/edit
def edit
#event = Event.find(params[:id])
#users = ['BG', 'BD', 'MB', 'AF', 'RA', 'JM']
#name = ['Brad Garrison', 'Brian Davis', 'Matt Broach', 'Alan McFarland', 'Russell Anderson', 'Jason Milam']
end
# POST /events
# POST /events.json
def create
#event = Event.new(params[:event])
respond_to do |format|
if #event.save
user = #event.name
Notifier.task_created(user).deliver
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render json: #event, status: :created, location: #event }
else
format.html { render action: "new" }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# PUT /events/1
# PUT /events/1.json
def update
#event = Event.find(params[:id])
#save = #event.update_attributes(params[:event])
#complete = CompleteEvent.new(:initials => #event.initials, :name => #event.name, :event_name => #event.event_name, :complete => #event.complete, :event_description => #event.event_description, :comment => #event.comment)
respond_to do |format|
if #event.update_attributes(params[:event])
if #event.complete == true
user = #event.name
#save
#complete
#complete.save
#event.destroy
format.html { redirect_to :controller => :events, :action => :index}
format.json { head :no_content }
elsif #event.complete == false
Notifier.task_updated(user).deliver
format.html { redirect_to :controller => :events, :action => :index}
format.json { head :no_content }
end
end
end
end
# DELETE /events/1
# DELETE /events/1.json
def destroy
#event = Event.find(params[:id])
#event.destroy
respond_to do |format|
format.html { redirect_to events_url }
format.json { head :no_content }
end
end
end
In edit.html.erb (or your partial that is rendered in edit.html.erb) use:
<%= form_for #event do |f| %>
You generally do not need to specify the action, since it is inferred from the URI path, and Rails knows the id for the model object is #event.id.
What I was missing was that my form was in a loop. Therefore when I was calling the form_for #event it couldn't see outside of that loop. I had the function take on the variable of event.
<% #events.each do |event| %>
......
......
<% form_for event do |f| %>
.....
<% end %>
Am having trouble getting the Atom feed function to work on my blog. I am using the Kaminari plug-in to paginate my articles - 6 per page. With the code below, when a user clicks on the RSS Feed image they are asked to log-in instead of subscribing to the feed! Any help would be appreciated with this issue...
application.html.erb
page head <%= auto_discovery_link_tag(:atom, feed_path, { :title => "My ATOM Feed" }) %>
page body <%= image_tag("feed.png", {:alt => 'Atom feed', :class=>"feed"}) %>Subscribe
routes.rb
match '/feed' => 'articles#feed', :as => :feed, :defaults => { :format => 'atom' }
articles_controller
class ArticlesController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show]
# GET /articles
# GET /articles.xml
# display articles on the home page
def index
#articles = Article.published.page(params[:page]).per(6).ordered
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #articles }
format.atom { render :atom => #articles }
end
end
# GET /articles/1
# GET /articles/1.xml
def show
#article = Article.find(params[:id])
#comment = Comment.new(:article=>#article)
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #article }
end
end
# GET /articles/new
# GET /articles/new.xml
def new
#article = Article.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #article }
end
end
# GET /articles/1/edit
def edit
#article = Article.find(params[:id])
authorize! :edit, #article
end
# POST /articles
# POST /articles.xml
def create
#authorize! :create, #article
#article = Article.new(params[:article])
#article.user_id = current_user.id
respond_to do |format|
if #article.save
format.html { redirect_to(#article, :notice => 'Worry was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "new" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
# PUT /articles/1
# PUT /articles/1.xml
def update
#article = Article.find(params[:id])
authorize! :update, #article
respond_to do |format|
if #article.update_attributes(params[:article])
format.html { redirect_to(#article, :notice => 'Worry was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.xml
def destroy
#article = Article.find(params[:id])
authorize! :destroy, #article
#article.destroy
respond_to do |format|
format.html { redirect_to(articles_url) }
format.xml { head :ok }
end
end
end
views/articles/feed.atom.builder
atom_feed :language => 'en-US' do |feed|
feed.title "mysite.com"
feed.updated(#articles.blank? ? Time.now : #articles.first.created_at)
#articles.each do |article|
feed.entry article, :published => article.accepted do |entry|
entry.title article.title
entry.author do |author|
author.name article.user.fullname
end
end
end
end
Update this line in your articles_controller:
before_filter :authenticate_user!, :except => [:index, :show]
... with:
before_filter :authenticate_user!, :except => [:index, :show, :feed]
This will prevent the request for authentication.
Two suggestions:
1) Add :url and :root_url to the atom_feed call.
2) Change:
feed.updated #articles.first.created_at
to:
feed.updated(#articles.blank? ? Time.now : #articles.first.created_at)
I am playing with rails 3.0.6 with ruby 1.9.2,
the app is working on browser but not in testing..
1) I created a new rails application by "rails new myapp"
2) Generate a scaffold "rails generate scaffold user username:string hashed_password:string salt:string"
3) after that, i changed the users_controller a bit
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully created.") }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
4) so i try to modify tests as well:
setup do
#input_attributes = {
:username => 'username#goodmail.com',
:password => 'secret',
:password_confirmation => 'secret'
}
#user = users(:one)
end
test "should create user" do
assert_difference('User.count') do
post :create, :user => #input_attributes
end
assert_redirected_to users_path
end
test "should update user" do
put :update, :id => #user.to_param, :user => #input_attributes
assert_redirected_to users_path
end
But the create and update tests failed
Can anyone let me know what had i done wrong?
Thanks
Loaded suite C:/Ruby192/lib/ruby/1.9.1/rake/rake_test_loader
Started
F.....F
Finished in 5.628874 seconds.
1) Failure:
test_should_create_user(UsersControllerTest) [test/functional/users_controller_test.rb:26]:
"User.count" didn't change by 1.
<3> expected but was
<2>.
2) Failure:
test_should_update_user(UsersControllerTest) [test/functional/users_controller_test.rb:45]:
Expected block to return true value.
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
require 'digest/sha2'
class User < ActiveRecord::Base
validates :username, :presence => true, :uniqueness => true
validates_format_of :username, :with => /\A^[^\r\n# ][^\r\n# ]+#[^\r\n# ]+[.][^\r\n#. ]+$\Z/i
#password is a fake field
validates :password, :confirmation => true
validate :password_must_be_present
attr_accessor :password_confirmation
attr_reader :password
def password=(password)
if password.present?
generate_salt
self.hashed_password = self.class.encrypt_password(password, salt)
end
end
class << self
def encrypt_password(password, salt)
Digest::SHA2.hexdigest(password + "shrimpy" + salt)
end
def authenticate(username, password)
if user = find_by_username(username)
if user.hashed_password == encrypt_password(password, user.salt)
user
end
end
end
end
private
def password_must_be_present
errors.add(:password, "Missing password") unless hashed_password.present?
end
def generate_salt
self.salt = self.object_id.to_s + rand.to_s
end
end
assert_redirected_to user_path is singular. You probably don't even have a singular user resource route defined. What you want there is probably assert_redirected_to users_path with a plural users.
I have two controllers: projects and stages.
Projects has many stages and stages belongs to projects. I want when you click on the name of the project (i.e. the projects show action), for it to show all the stages related to that project.
How do I do that ?
All of the relevant code can be found below:
Stages Controller
class StagesController < ApplicationController
filter_resource_access
# GET /stages
# GET /stages.xml
def index
#stages = Stage.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #stages }
end
end
# GET /stages/1
# GET /stages/1.xml
def show
#stage = Stage.find(params[:id])
##project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #stage }
end
end
# GET /stages/new
# GET /stages/new.xml
def new
#stage = Stage.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #stage }
end
end
# GET /stages/1/edit
def edit
#stage = Stage.find(params[:id])
end
# POST /stages
# POST /stages.xml
def create
#stage = current_user.stages.create(params[:stage])
##stage = Stage.new(params[:stage])
respond_to do |format|
if #stage.save
format.html { redirect_to(#stage, :notice => 'Stage was successfully created.') }
format.xml { render :xml => #stage, :status => :created, :location => #stage }
else
format.html { render :action => "new" }
format.xml { render :xml => #stage.errors, :status => :unprocessable_entity }
end
end
end
# PUT /stages/1
# PUT /stages/1.xml
def update
#stage = Stage.find(params[:id])
respond_to do |format|
if #stage.update_attributes(params[:stage])
format.html { redirect_to(#stage, :notice => 'Stage was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #stage.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /stages/1
# DELETE /stages/1.xml
def destroy
#stage = Stage.find(params[:id])
#stage.destroy
respond_to do |format|
format.html { redirect_to(stages_url) }
format.xml { head :ok }
end
end
end
Stages model:
# == Schema Information
# Schema version: 20101124095341
#
# Table name: stages
#
# id :integer not null, primary key
# project_id :integer
# created_at :datetime
# updated_at :datetime
# user_id :integer
# name :string(255)
# stage_num :integer
class Stage < ActiveRecord::Base
belongs_to :projects
#has_and_belongs_to_many :users
has_many :uploads
has_many :comments
end
Projects Model
# == Schema Information
# Schema version: 20101117094659
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255)
# description :string(255)
# designer_id :integer
# client_id :integer
# notified :boolean
# created_at :datetime
# updated_at :datetime
# user_id :integer
class Project < ActiveRecord::Base
belongs_to :user
has_many :stages
has_many :uploads
has_many :comments
#before_validation { |project| project.user = Authorization.current_user unless project.user }
end
Project Controller
class ProjectsController < ApplicationController
filter_resource_access
# GET /projects
# GET /projects.xml
def index
#projects = current_user.projects
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #projects }
end
end
# GET /projects/1
# GET /projects/1.xml
def show
#project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #project }
end
end
# GET /projects/new
# GET /projects/new.xml
def new
#project = Project.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #project }
end
end
# GET /projects/1/edit
def edit
#project = Project.find(params[:id])
end
# POST /projects
# POST /projects.xml
def create
#project = current_user.projects.create(params[:project])
respond_to do |format|
if #project.save
format.html { redirect_to(#project, :notice => 'Project was successfully created.') }
format.xml { render :xml => #project, :status => :created, :location => #project }
else
format.html { render :action => "new" }
format.xml { render :xml => #project.errors, :status => :unprocessable_entity }
end
end
end
# PUT /projects/1
# PUT /projects/1.xml
def update
#project = Project.find(params[:id])
respond_to do |format|
if #project.update_attributes(params[:project])
format.html { redirect_to(#project, :notice => 'Project was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #project.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /projects/1
# DELETE /projects/1.xml
def destroy
#project = Project.find(params[:id])
#project.destroy
respond_to do |format|
format.html { redirect_to(projects_url) }
format.xml { head :ok }
end
end
end
Projects Show View
<p id="notice"><%= notice %></p>
<br />
<% #projects.each do |project| %>
<% #stages.each do |stage| %>
<tr>
<td><%= link_to stage.name, stage %> | </td>
<td><%= stage.stage_num %> | </td>
<td><%= link_to 'Show', stage %></td>
<td><%= link_to 'Edit', edit_stage_path(stage) %></td>
<td><%= link_to 'Destroy', stage, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
<% end %>
<% if permitted_to? :create, Stage.new %>
<%= link_to 'New Stage', new_stage_path %>
<% end %><br /><br />
<%= link_to 'Edit', edit_project_path(#project) %> |
<%= link_to 'Back', projects_path %>
There are many ways to do this. The easiest way to accomplish this with your existing code is to change the projects show view page.
replace this:
<% #projects.each do |project| %>
<% #stages.each do |stage| %>
with:
<% #project.stages.each do |stage| %>
Then, you would use the "index" view to show all the projects and the "show" view would be to show project specifics (which would include stages)