Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Currently i am learning rails so i'm sorry for my bad knowledge and probably for a silly question. :)
I created a simple index page in a controller called pages.
Inside index.html.erb i have a form where a user can sign up for a newsletter which is stored in #newsletter and i also have a variable called #title where title of the page is stored in database.
I want to create an administration panel available only for the owner of the website where he can access and display all newsletters, also i would like the owner to have the possibility to change the title.
Can i achieve that if i create another controller ?
What do you recommend, to keep the same controller for admin and pages or create a new controller for admin area ?
Also, one more question, when do i need to create a model? Everytime when i need a new table in database, isn't ?
I should have a single model for every controller or i can have more models and one controller?
Is there any connection between pages and the newsletter?
If newsletter is not in a relationship with pages, then you can place the newsletter form in a partial and render it where you want.
This a possible db schema for you:
'Page.rb' model with the fields that you need like: title:string, slug:string (i prefer friendly_id), body:text...
'NewsletterEmail.rb' model with the fields that you need: email_address:string, name:string (optional), subscription_status:boolean (to track un-subscription)...
Every model needs a controller for you to track in admin.
For the front-end, you must setup a route like 'match: "/:slug" => "public#page"', where you can catch your page like #page = Page.friendly.find(:slug) and then assign the #title variable #title = #page.title.
Hope this helps you.
For your admin controllers pages_controller.rb and newsletter_emails_controller.rb you can use a before_action :check_admin_rights and define in application_controller.rb
def check_admin_rights
authenticate_or_request_with_http_basic('Administration') do |username, password|
username == 'admin' && password == 'password'
end
end
Related
I am trying to create a comment model for my posts and the question is how am I able to create comments but not have the routes nested inside of the posts...
That is, there is no route to posts/comment/:comment_id and instead just have the user enter a comment and let the user stay on the page without having to transfer the user. I want the user to have no interaction with a different route and just have them say where they are.
Not sure I understand correctly, but if you don't want the user to be taken to a new page after creating a comment just remove the "render" method in the action for the comment controller.
I have a model Post, which is submitted and graded by different Users. The submitter and grader are identified by submitter_id and grader_id in Post model. Note that an user is both a submitter himself and a grader to others.
I want to make sure that the submitter can only edit the content of the Post but not the grade. Likewise, the grader can only edit the grade but not the content.
Is multiple edit methods the way to go? How should I accomplish this otherwise?
You can have a role column in your users table, and the role can be either submitter or grader. Not sure what you are using for authentication, but in case you are using devise, you can access the currently logged in user with current_user helper (in case you are using something else, figure this part out, or add a new helper).
Now in your update method, you can do something like this:
# Controller
# scope post to current user, so that a user cannot edit someone else's post. A crude way to achieve this is post = Post.find(params[:id])
post = current_user.posts.find(params[:id])
post.content = params[:content] if post.submitter?(current_user.id)
post.grade = params[:grade] if post.grader?(current_user.id)
post.save!
# Model - Post.rb
def submitter?(user_id)
self.submitter_id == user_id
end
def grader?(user_id)
self.grader_id == user_id
end
The advantage of keeping those methods in the model is that in case you permission logic changes (who is submitter, or a grader), you need to change it at a single location. DRY.
You can modify the above approach to show error messages, and do other similar stuff. In case you are looking for more granular authorization control, you can look into cancan gem:
https://github.com/ryanb/cancan
Your post model should only be concerned with persisting data. Better to use plain old ruby objects to encapsulate the higher order behavior of grading and submitting. Consider using service objects or form objects.
Each service or form object can then include ActiveModel::Model(rails > v4) to get its own validations.
See more about service and form objects here: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
If you only have one submit action and one grade action, its probably ok to keep in one controller. But if you start having multiple actions that are related to submitted, and multiple actions that are related to grading, this sounds like they would make great resources controllers on their own.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Here's what I need to achieve :
A user visit the login page. Upon the first visit, the browser will record his IP and data from a cookie (cookies[:user]) and send it to the server. The server then check whether the IP or the user is in the block list and if the user is in the block list, it will automatically redirect the use to a blocked page!
Can we do this in Rails and how?
This could be done quite easily, take this for example
def new
if cookies[:userid].present?
if User.find(cookies[:userid]).userblocked == true
redirect_to "/block_page"
end
elsif #failedtries == max_tries
User.find(cookies[:userid]).userblocked = true
cookies[:userid] = #id_entered
end
end
Where 'userblocked' is a true or false value in your database. This method is full proof against people who can freely change their IP. However if your heart is set on using IP's then this is an example:
def new
if cookies[:blocked].present?
redirect_to "/block_page"
else
if BlockedIps.find_by_ip(request.remote_ip).blocked == true
redirect_to "/block_page"
elsif #failedtries == max_tries
BlockedIps.find_by_ip(request.remote_ip).blocked = true
cookies[:blocked] = true
end
end
end
Something like this could be what you are after. Give it a try, I haven't tested the code. This is just from my head at this moment in time, but it should do what you want, providing you have some sort of system to store the IP in a database when the max tries have reached.
Explanation:
The way it works is that it checks to see if the blocked cookie is present, if so it redirects to the block page, if not it checks to see if the users IP address is in the block list of IP's. If the IP is present and the block column is set to true then the user will be redirected to the block page, else the system checks how many tries they have made and if it is equal to the max tries it adds the users IP to the database and creates a cookie on their PC which can be checked on next visit.
You can make a method for checking the IP address and authenticating then use before_action :yourmethod on top of your controllers. before_action runs before any other action in your controller so it is a good way to authenticate before showing any views.
You can use Conner Stephen McCabe solution above or take a gem for this purpose.
User can easily clear the cookie, so it's not safe anyway.
Example: https://github.com/kickstarter/rack-attack
I am working on a Ruby on Rails 3 web application.
I have a table named User with a coulmn named role. I am looking for the best way to hide parts of the view from users that have the "wrong" role for those parts of the view.
For example I want all users to be able to see the users index page, but i want only users with a role - admin to be able to edit other users.
So first I block the edit action using filter_by, but what I also want is make the edit button not to appear.
The current user is saved in the session, so checking the user role is very simple.
What I am asking, is there an easy way to do so besides the obvious if statement before each button I want to hide. I would think that rails would have an easy way to do this type of thing, I couldn't find one.
You may want to use Devise and CanCan.
https://github.com/plataformatec/devise
https://github.com/ryanb/cancan
Here is a RailCast tutorial
http://railscasts.com/episodes/192-authorization-with-cancan
if you wanted to clean it up a tiny bit you could write yourself an application helper:
def if_admin(user)
if(user.is_admin? && block_given?)
yield
return
end
end
then in your view you could write:
<% if_admin(#user) do %>
<some admin only html />
<% end %>
I am currently building a Rails app, and trying to figure out the best way to authenticate that a user owns whatever data object they are trying to edit.
I already have an authentication system in place (restful-authentication), and I'm using a simple before_filter to make sure a user is logged in before they can reach certain areas of the website.
However, I'm not sure the best way to handle a user trying to edit a specific piece of data - for example lets say users on my site can own Books, and they can edit the properties of the book (title, author, pages, etc), but they should only be able to do this for Books that -they- own.
In my 'edit' method on the books controller I would have a find that only retrieved books owned by the current_user. However, if another user knew the id of the book, they could type in http://website.com/book/7/edit , and the controller would verify that they are logged in, then show the edit page for that book (seems to bypass the controller).
What is the best way to handle this? Is it more of a Rails convention routing issue that I don't understand (being able to go straight to the edit page), or should I be adding in a before_find, before_save, before_update, after_find etc callbacks to my model?
check out the following gems:
cancan
devise
authlogic
and don't miss Ryan's great railscasts on the above
this will give access to anyone who changes the value in the address bar
#book = Book.find(params[:id])
but if you go through the association of the logged on user rails (ActiveRecord) will automatically update the sql query
#book = current_user.books.find(params[:id])
of course this assumes that your books table has a user_id column
You may need an authorization plugin. I had some experience use this plugin a while back. This article also has an overview:
You might also take a look at Declarative Authorization
Hey I have recently done this myself. The easiest way to do this is to have the edit feature display on the page but incase it in a method such as the following:
<%if current_user %>
<% if current_user.id == wishlist.user_id %>
<div id="text3"><%= link_to 'Edit', edit_wishlist_path(#wishlist) %></div><br />
<%end%>
<%end%>
Is this what you were hoping for?