I am a beginner in Grails 2.0 framework and I am trying to follow this tutorial http://grails.org/Simple+Avatar+Uploader . I implemented this code but I am getting an error in UserController.groovy at this line 'def user = User.current(session)' as ' No such property: User for class: grailtwitter.PersonController' I assume that this line takes the user's current session. I am looking for an explanation of how this works ?
This code is incomplete. The controller presupposes that you have a way of identifying the currently logged in user. Implicitly the line def user = User.current(session) assumes that you have defined a current() method on the user class itself that takes in a session and presumably uses some field that you've set in it to retrieve a User. That would be kind of dumb.
A common way to do this would be to build your own authentication mechanism. Note that this is a naive practice and you are far better off using Spring Security Core unless you want to leave your application open for gaping security holes. But, for practice, something like:
def login = {
//if you're stupid enough to store your passwords in plain text and not sanitize user inputs, you deserve to be hacked
def user = User.findByPassword(params.password)
if(user){
session.user = user
}
}
You could then replace the offending line in the tutorial (--def user = User.current(session)--) with
def user = session.user ?: new User(userid:"I'm a little teapot")
Before you go much further, you probably want to walk through this free eBook on Grails before you get much further. Also highly recommend Grails in Action.
When I have run into this in the past it's because I didn't import the class and Grails/Groovy thinks I'm trying to access a variable called User rather than a method on the class.
Related
I'm working on a wizard - a PORO module - for user's information. The goal is to forward the users to said wizard for him to complete his user profile if he attempts to make a booking (or similar action) with an incomplete profile.
After the last step of the wizard I would like to redirect the user back to the action he intended initially. For that I'm saving a session variable named ":user_return_to_from_wizard".
I can't seem to access the session variable from the PORO module. What can I do?
I tried of course
session[:user_return_to_from_wizard]
but that doesn't work. I guess something like
App::Application.session....
You probably can't and should'nt - one of nice things of using PORO is to be able to use them outside of a specific context (HTTP and session in your case). What I would do is collect the information you need from the session and use it to initialize your wizard:
class SomeController < ApplicationController
def index
return_url = session[:user_return_to_from_wizard]
wizard = Wizard.new(return_url: return_url)
...
end
end
This way you can still test/use Wizard independently and don't have to rely on session inside.
I am fairly new to rails and am just getting into using cool gems and APIs. I have been made aware that this community values the contents of questions and answers, or it is expected that they are constructed in a specific way. The short way to ask my question and the long way are provided. Please let me know which is preferred here! It is a real question though!
SHORT VERSION
I have a users_controller and User object with a username attribute in a rails app. How do I create global variables for these users that is dynamically based on their username? Example: I want with my user (id = 1, first_name = "Rob", username = "rocky") to be callable as #rocky. So what would go below in my Users_controller that is based on the first code line below working for me in terminal:
#rocky = User.find_by_username("rocky")
WHATGOESHERE = User.find_by_username(params[:username]}
or should I be using this in some shape or form in place of params[:username]
#"#{user.username}"
Below is the longer version of my question. It is more detailed and follows more closely how I approached the issue. The first one... that I wrote second, is more concise but that's not always what people want... please let me know which is preferred on this site. Thanks!!
LONG VERSION
I need some clarity on a few things. I am using a gem called "has_friendship" to create friendships between my users (link to gem- https://github.com/sungwoncho/has_friendship ).
First, this is the documentations example of how to request a friendship, starting with the creation of the users.
#mac = User.create(name: "Mac")
#dee = User.create(name: "Dee")
# #mac sends a friend request to #dee
#mac.friend_request(#dee)
This is where I first became confused. My users don't have a "name" field. But that's ok. I managed to figure out that I just need to assign my created users global variables as they do... since my users will be interacting with each other behind their "username" attribute. So first question, How do I assign a dynamic variable name to each user? In the documentation, they are hard-coding in the names "Mac" and "Dee." I need to have this global variable be created upon the creation of the object.. So my plan is to do this in the controller. Here I am already defining #users and #user in users#show
#users = User.all
#user = User.includes(:wallet).find_by_id(params[:id])
So my thought process is that the left side of the equation should be the name of what you're naming and the right side is what that name is referring to. So for the right side, I'd think to put
User.find_by_username(params[:username])
as when in the terminal, if I replace the content in parenthesis with an actual username in quotes, it brings up that user's info. So how do I write the left side. I would think the left side is something like this:
#"#{params[:username]}"
So in full I currently have the following in my users_controller to assign global variables to my users based on their username atttribute...
#"#{params[:username]}" = User.find_by_username(params[:username])
This, especially the left side, does not look at all right to me. So I've looked around on google a bunch and the only other thing I can find that looks like the right way to do this is by using "instance_variable_set" but everything I've looked at doesn't make total sense for my situation... (as usual.. ha)
Ok what I get to know from your question is you want to use friend_request method to associate two users.
For this, you don't need to assign them to any variables. You can directly do this by something like this -
Suppose there are two user's
id=1 first_name='Rocky' username='rocky'
id=2 first_name='Nimish' username='nimish'
User.find_by(username: 'rocky').friend_request(User.find_by(username: 'nimish'))
OR
User.find_by_username('rocky').friend_request(User.find_by_username( 'nimish'))
Also, If you want to assign them to instance variable then it is not necessary to create an instance variable corresponding to the username value
You can simply assign them to #user and #requested_user and then
#user.friend_request(#requested_user)
Working through authentication in RailsCasts, there was one where I didn't understand something completely fundamental and important (it's pro, sorry - you need to be subscribed to access it).
He creates a user model with an email and encrypted password (has_secure_password).
Then he makes a new controller called Sessions, and declares it as a resource in the config. i.e.
resources :sessions
Then, inside the sessions controller, he defines the create method like this:
user = find user and authenticate
if user
session[:user_id] = user.id
else ...
But sessions as a model doesn't exist. For instance, if I open up my console and write
sessions[:user_id] = "hello"
it throws. Does anyone have an explanation or a link to this very basic concept that I'm missing?
Thanks!
Edit: Thanks Sanfor. Typo fixed, also for markup plus most importantly an answer!
I suppose you have copied the session as sessions in your question, is that correct? The screen cast is revised, so you'd need to be subscribed what I'm not nowadays so can't confirm it more than what comments say.
Now to the actual answer, the session is Rails internal reference to the actual session on hand as described here and for that reason you can't see the model for it created.
Simplistic explanation:
session is just a hash and stored as a cookie. (Unless you specifically instructed Rails to store it in the database). Models are typically ActiveRecord based and have some behavior.
You can add to it by simply
session[:some_thing] = "Info for session"
session[:store_this_too] = "Some other info to track for this session"
The session hash is created by the controller-related class/modules and rails console doesn't load them. Therefore, it is not available in the console.
Here's a pretty old Railscasts which explains a bit more. And this which takes the model-based approach. Bear in mind they are from the old days.
I want to learn how to create my own authentication system, please provide some guidance if am doing this wrong.
I will create a Module in my /lib folder /lib/auth.rb
I will require this module in my ApplicationController.
when a user enters their email + password, I will call a method that will do a lookup in the user's table for a user with the same email, I will then compare the passwords. (i'll add encryption with salt later).
If the user entered the correct credentials, I will create a row in the Sessions table, and then write the session GUID to a cookie.
Now whenever I need to check if the user is logged in, or I need the user object, I will check if the cookie exists, if it does, I will lookup the session table for a row with the same guid, if it exists, I will return the session row and then load the User object.
I realize there are many suggestions one can give, but in a nutshell does this sound like a workable solution?
Now to make this usable, I will have to make some helper methods in my ApplicationController right?
How will I access the current_user from within my views?
P.S I know of other authentication systems, I just want to learn how to create my own.
The basic logic you're following is correct. Of course you can always expand on this with features that you need. For instance, you'll need helper methods for things like "logged_in?" and "current_user". Also, you might want to add session expiry, or session retention as a "remember me" feature.
Go for it, you won't learn authentication systems better than building your own then figuring what's wrong with it.
You should really check out the authlogic gem on github.
http://github.com/binarylogic/authlogic
It also has great instructions on how to set up your users.
After Faisal said what I would say, I only give you answer to the last part of your question:
"How will I access the current_user from within my views?"
try something like this:
class User < ...
def self.current=(u)
#current = u
end
def self.current
#current
end
end
In your views (or any part of your code) you can call User.current. Your controller has to assign a validated user to User.current. Your filters can react to "if User.current.nil?" and so on.
If you want to be thread safe, you may use a thread variable instead of #current:
Thread.current[:current_user] = u
I use RoR 3 and i guess something changed in controller's tests.
There is no
def test_should_create_post
but
test "should create user" do
...
end
Is there any decription how is that mapping etc? Because i dont get it.
And second thing. How to program (what assertion) use to test login?
so the test "something here" style is rails way of helping us out. It is fundamentally the same as def test_as_you_want but they helped us out by taking away those nasty '_(underscores)' and wrapping the actual test wording in a string. This change came back, phew... maybe 2.3.x. that fact has to be checked but at least a year and a half ago.
Your second thing is a little more harder to answer man. What plugin are you using, or are you one of those guys who are writing their own auth system?
Either way, check out how the 'famous' auth plugins do it. from Restful Auth to Devise, basically you want test that you can:
Signup for the User account
all of your confirmation emails are sent etc..
Most of these 'cheat' or take the easy way out by passing a helper called signed_in users(:one) for instance. Assuming you are cool and using fixtures.
Basically here is what a helper method looks like if your Auth plugin/gem doesn't have one, like Clearance which didn't have it when i was first writing my tests... not sure if it has it now but it sheds light on how it should look. Notice I've commented out Restful Auth and how he/they did it:
#login user
def login_user(user = users(:one))
#Restful Auth Example
# #request.session[:user_id] = user ? users(user).id : nil
# Clearance
#controller.class_eval { attr_accessor :current_user }
#controller.current_user = user
return user
end
Actually i think i stole this from their shoulda login helper... that's probably what i did. Either way it shows you how to fake login a user.
Now when you are testing, just pass this login_user method to your test when you need a user logged in and start testing the rest of the method without worrying about them actually signing in. That is what the plugin is supposed to do and the 1000 people following it on github would scream if it didn't at least LOG that guy in.
cheers