Making sure I got the idea . - Ruby on rails login system - ruby-on-rails

I am currently reading a book, and learning ruby on rails. (Agile Web Development with Rails 4th Edition) .In the book it says how to write a simple product list and display it. I am modifying this idea, to create a user login system.
I am only working on the views now.
So I just need to make sure that my idea is right. My idea is:
The show.html file from the USER model, show data for one user. (given of course its ID)
for example : http://localhost:3000/users/980190974 will give me the html page for the current user right? Now I can allow the user to edit his/her information by using the
<%= link_to 'Edit', edit_user_path(#user) %> link or restrict him from viewing other users by removing the <%= link_to 'Back', users_path %> << that lists all the users from the database. But before the user views his/her details he must login, using his email and password. So by making an html page, that takes 2 strings (username, and password) searches my mySQL database and return the user ID , that I then use to "render" the user's HTML page.
Is my way of thinking correct? Or am I just completely irrelevant on how Ruby on Rails works? O_o

You are heading in the right direction. One thing to point out is that simply removing the link <%= link_to 'Back', users_path %> is not sufficient to avoid other users from accessing the /users path. In the (user) controller you have to use something like:
class UserController < ApplicationController
def index
unless current_user.is_admin
redirect_to user_path(current_user)
return
end
... rest of code here
end
end
where current_user could be a method returning the user object

Related

Rails issues with authentication

I am building my first app using rails and i am struggling to give an account to each user. Its a simple app where a user creates a post and saves it. this post can be seen on index page. Until now we are ok. when i sign out, i register a new user and i log in. when i go to the index page, i can see what other user has saved. I want to have a private index page for each user where no one can see what users are saving in their app. I am using Gem 'Device" to authenticate my app, but i don't know how to make private their account? any ideas?
You have implemented authentication. Now you need to build authorization.
You have to define what data can be accessed by user.
Take a look at:
CanCanCan
With devise authentication technique, after logging in the user you can write a clean piece of code to render the posts of the logged in user. You can use session data to do it. the current_user helper method returns the model class relating to the signed in user. With devise, it ensures after authentication that, it has the helper methods ready to be used. So, the error with no such user with that id can be avoided.
#web/controller/post_controller.rb
before_filter :authenticate_user!
def list
#posts = current_user.posts
end
And then, use #posts in the list view to render the posts of the logged in user only.
<% #posts.each do |post| do%>
<%= post.content %>
<% end %>

create edit URL route that doesn't show :id

I'm in the midst of trying to clean up my routing. I have a company model that can log in and create applications. They can create several.
Currently this is my setup:
Routes
get 'applications/edit/:id', to: 'applications#edit'
Applications_controller
def edit
#application = current_company.applications.find(params[:id])
end
def update
#application = Application.find(params[:id])
if #application.update(application_params)
redirect_to dashboard_path
else
render 'edit'
end
end
Each company have their own dashboard. Here's my code from
/dashboard
Your active applications
<% #applications.all.each do |f| %>
<%= link_to "Application", show_path + "/#{f.id}" %> | <%= link_to "Edit", edit_application_path("#{f.id}") %>
<br>
<% end %>
Now this all works, if I go to edit_application/11 f.ex I see it.
The thing I'd like changed is to remove the :id from the URL.
Thus make it more secure and to give a nicer feel. Now it took me 5 minutes before I realised I could just change the :id url and edit everything. Thus I added the current_company.applications to stop that. Yet I don't feel like this is very secure.
If you want to remove the :id, you'll still need a way to find the data you want.
As long as you have the url /edit/12 and as long as you use the id 12 in the GET url to find your content, it will show in the browser bar. The only way to "hide" it (but it's not more secure at all, because it's easily found out), is to use a POST request with a form containing a hidden field with the id (can be made in JavaScript).
You are asking the application to get the id from the link in the #applications.all.each but the only way it can do that is to include it somewhere in the request (be it GET, POST, COOKIES/SESSION, ...).
For another (possibly better) solution, read on.
A very common practice is to use slugs: you create a unique key for each content, for example, if your title is "My great app", the slug will be my-great-app. Thus there is no id in your URL (and it cannot be found out if you always use slugs as references). The advantage is that you'll still find a quick match for what you're searching for (creating an unique index on the slugs).
Some further reading about slugs:
http://rubysnippets.com/2013/02/04/rails-seo-pretty-urls-in-rails/
What is the etymology of 'slug'?

How to do browser-based new user approval by Admin in Rails 3.2 using Devise

I created a simple directory using Rails 3.2 and devise where new users need approval before they can use the site. I followed the instructions in "How To: Require admin to activate account before sign_in" and admin users can now see lists of different index pages of approved versus non-approved users. So far so good.
My problem is the user approval process. Currently I approve users in the Rails console. I'd like for admin users to be able to approve users through their browser. I'm at a loss. I know I need to put "approve" and "don't approve" links next to each unapproved user but then what?
In the abstract I know that clicking those links should activate a method in the User model or controller and then redirect with flash but I've strayed beyond what I know from my beginner tutorials.
I'm not sure what to put in my views and routes. Do I need a special hidden form that only changes 'approved' from false to true when when the "approve" submit button is clicked and the button is the only visible element?
If anyone can get me started in the right direction I can probably figure it out from there.
#sas1ni69's comment lead me to Ruby on Rails link_to With put Method which allowed me to find a solution.
To my view I added:
<%= link_to "approve", approve_user_path(user.id) %>
To my routes I added:
match 'users/:id/approve'=> 'users#approve_user', as: 'approve_user'
To my user controller I added:
def approve_user
user = User.find(params[:id])
user.approved = true
if user.save
flash[:notice] = "#{user.full_name} approved"
else
flash[:alert] = "#{user.full_name} approval failure"
end
redirect_to :back
end
Seems to be working like a charm! Thanks everybody!

How can I have the user only add their #name instead of entire Twitter link in a url_field?

In my Rails app I have a user model (Devise) with url_field for Twitter.
Right now I have this in my show page:
<%= link_to #deal.user.company_twitter, #deal.user.company_twitter, :class => "comp_twitter" %>
It shows the entire link in the show page (even http://), that's because my url_field makes the user add "http://" or it won't validate the link.
I want the user to only add their "#name" instead of the whole Twitter link when creating their profile. I would also want to show only the #name instead of the Twitter link in the "show" page. How can I do this?
Simply don't use an url_field, but a regular string database field, like twitter_username. When signing up, let the user enter their username, e.g. foo.
For getting the real URL to the Twitter account, create a new method in your user.rb model:
def twitter_url
"http://twitter.com/#{self.twitter_username}"
end
The advantage is that at this point, in your model, you can include a custom validation that would check if this URL really exists after the user has submitted their twitter_username.
Finally, use that in your view instead of just the URL:
<%= link_to "##{#user.twitter_username}", #user.twitter_url %>
This would render:
#foo

Helper method for url?

I have multiple fields for social networking websites where users can enter their username and it would link to their twitter, facebook, myspace account etc. My problem is how can I have it so when a user enters their username I can link to their account.
Here's what I have and I know this is probably not correct. In my profile index.html
<%= link_to twitter_url %>
profile helper method
def twitter_url
return(self.url= "http://twitter.com/#{profile.twitter}/account")
end
In my profile controller
include ProfilesHelper
The actual field in database is called
twitter_link
How can I get the just the user username then on my part which will do the rest link to their twitter, facebook etc account page?
How is that method supposed to know what the profile object is without you passing it in?
I'm imagining there being a #profile variable defined in your controller. In the view, you would have this:
<%= link_to twitter_url %>
And in the helper, this:
def twitter_url
"http://twitter.com/#{#profile.twitter_link}/account"
end
Note here that you don't need to set self.url or have an explicit return. This is because the method will automatically return a String which is what link_to takes.
If you want this method to be in a helper that's available in just your ProfileController, then why not put it inside ProfileHelper so that it's automatically included just by being related by name?

Resources