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.
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
I have a model called Test that accepts_nested_attributes_for SubTest. A Test basically has an id, and there are multiple SubTests associated with an individual Test.
I want to validate that an attribute of the SubTest is numeric. Here are my models so far.
class Test < ActiveRecord::Base
has_many :sub_tests
accepts_nested_attributes_for :sub_tests
end
class SubTest < ActiveRecord::Base
belongs_to :test
validates :measurement, :numericality => true, :allow_nil => true
end
Here is the Test controller
def create
respond_to do |format|
if #test.save
flash.now[:notice] = "Test Created"
format.html { redirect_to(#test) }
format.xml { render :xml => #test, :status => :created, :location => #test }
format.js
else
flash.now[:error] = "[Error] Test Not Created Because: #{#test.errors.full_messages.join(", ")}"
format.html { render :action => "new" }
format.xml { render :xml => #test.errors, :status => :unprocessable_entity }
format.js
end
end
end
I want the create action in the controller to throw an error if the user enters a non-numeric string in the form for the sub_test.
Currently, if I enter non-numeric values for a sub_test.measurement, Rails doesn't create the Test or SubTest objects (desired behavior). But for some reason no error is thrown, and the Test controller triggers the create.js.erb partial.
I'm getting the impression that the validation for the numericality of sub_test.measurement should actually happen in the Test model, but I'm not sure how to write a custom validation method that tests for numericality.
Thanks in advance!
Got it. I needed to specify an _error.js.erb partial in my Test controller.
def create
respond_to do |format|
if #test.save
flash.now[:notice] = "Test Created"
format.html { redirect_to(#test) }
format.xml { render :xml => #test, :status => :created, :location => #test }
format.js
else
flash.now[:error] = "[Error] Test Not Created Because: #{#test.errors.full_messages.join(", ")}"
format.html { render :action => "new" }
format.xml { render :xml => #test.errors, :status => :unprocessable_entity }
format.js { render :partial => 'error' }
end
end
In the error partial I just appended my #messages div (since I'm doing form submissions through ajax.)
upload controller
def create
#upload = #order.uploads.build(params[:uploadtwo])
respond_to do |format|
if #upload.save
format.html { redirect_to root_path, :notice => 'File was successfully uploaded.' }
format.json { render :json => #upload, :status => :created, :location => #upload }
else
format.html { render :action => "new" }
format.json { render :json => #upload.errors, :status => :unprocessable_entity }
end
end
upload model
belongs_to :order
order model
has_many :uploads
i get error [NoMethodError in UploadtwosController#create ], [undefined method `uploads' for nil:NilClass]
anybody knows what am not doing?
Just declaring belongs_to :order in your Upload model does not mean that #order will automatically be defined in the controller. Perhaps what you want is a before_filter in the controller which will set #order?
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 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>