I'm trying to learn RoR by creating an application, however, I have come across a problem and I'm not sure if my method is flawed or if it's the correct way to do it but I'm going about it slightly wrong. I think it has something to do with the variable being an instance variable and it's not called in my other controller but I'm not sure how to get it there?
Anyway the problem is -
I have a todos controller, models, views etc. set up via the scaffolding in Rails but I want to be able to display the todos to each user in their 'dashboard' so to speak when they log in. Therefore I assume I need the todos to be in the dashboard controller too, right?
Here's my dashboard controller
class DashboardController < ApplicationController
def home
#todos = current_user.todos
end
end
Here I'm calling my todos but they aren't showing when I call them in the view.
and my todos scaffold
class TodosController < ApplicationController
before_action :set_todo, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /todos
# GET /todos.json
def index
#todos = current_user.todos
end
# GET /todos/1
# GET /todos/1.json
def show
end
# GET /todos/new
def new
#todo = Todo.new
end
# GET /todos/1/edit
def edit
end
# POST /todos
# POST /todos.json
def create
#todo = current_user.todos.new(todo_params)
respond_to do |format|
if #todo.save
format.html { redirect_to #todo, notice: 'Todo was successfully created.' }
format.json { render :show, status: :created, location: #todo }
else
format.html { render :new }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /todos/1
# PATCH/PUT /todos/1.json
def update
respond_to do |format|
if #todo.update(todo_params)
format.html { redirect_to #todo, notice: 'Todo was successfully updated.' }
format.json { render :show, status: :ok, location: #todo }
else
format.html { render :edit }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# DELETE /todos/1
# DELETE /todos/1.json
def destroy
#todo.destroy
respond_to do |format|
format.html { redirect_to todos_url, notice: 'Todo was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todo
#todo = Todo.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def todo_params
params.require(:todo).permit(:title, :item)
end
end
How would I go about displaying my todo items in the dashboard?
Thanks for any help
You just need to add
before_action :authenticate_user!
to DashboardController like the way you have it in TodosController .
Do you have a current user in the dashboard controller? You will need to decide how to handle that - either require sign in, or use an if else statement e.g.
def home
if current_user
#todos = current_user.todos
end
end
Related
I'm trying to enter a list of new modules and when I press 'new module list' which should take me to the form to fill out it throws up the error from the title. The application trace points at the bottom, the code inside 'def module_list_params' and also just above it where 'def set_student' is. I have no idea why it's doing it. I'm using ruby on rails.
class ModuleListsController < ApplicationController
before_action :set_module_list, only: [:show, :edit, :update, :destroy]
before_action :set_student, only: [:new, :create]
# GET /module_lists
# GET /module_lists.json
def index
#module_lists = ModuleList.all
end
# GET /module_lists/1
# GET /module_lists/1.json
def show
end
# GET /module_lists/new
def new
#module_list = #student.module_lists.new
end
# GET /module_lists/1/edit
def edit
end
# POST /module_lists
# POST /module_lists.json
def create
#module_list = #student.module_lists.new(module_list_params)
respond_to do |format|
if #module_list.save
format.html { redirect_to #module_list, notice: 'Module successfully created.' }
format.json { render :show, status: :created, location: #module_list }
else
format.html { render :new }
format.json { render json: #module_list.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /module_lists/1
# PATCH/PUT /module_lists/1.json
def update
respond_to do |format|
if #module_list.update(module_list_params)
format.html { redirect_to #module_list, notice: 'Module list was successfully updated.' }
format.json { render :show, status: :ok, location: #module_list }
else
format.html { render :edit }
format.json { render json: #module_list.errors, status: :unprocessable_entity }
end
end
end
# DELETE /module_lists/1
# DELETE /module_lists/1.json
def destroy
#module_list.destroy
respond_to do |format|
format.html { redirect_to module_lists_url, notice: 'Module list was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_module_list
#module_list = ModuleList.find(params[:id])
end
def module_list_params
params.require(:module_list).permit(:student_id, :title, :description, :credit_value)
end
def set_student
#student = Student.find_by(id: params[:student_id]) ||
Student.find(module_list_params[:student_id])
end
end
Rake routes screenshot
I believe your issue is the line before_action :set_student, only: [:new, :create]. set_student is being run when you go to the page with the form, but since there is no student_id included in the URL, it can't find anything to set it to.
To create a dependent object, there are two main ways: you can either have a form page tied to a specific parent object already, ie /students/4/module_lists/new, in which case submitting the form will create a module list tied to the student with an ID of 4. The other way is to have a general form not tied to any specific parent object, with some way of selecting a parent inside the form, eg a select or something. In that case the url would just be something like /module_lists/new.
If you want to go the first route, you'll want to nest the resources :module_lists inside of students. Check out the docs for how to do that, but it would basically look like
resources :students do
resources :module_list
end
And then in the link_to you click to go to that page, you'll need to pass in the student_id:
link_to 'Create Module List', new_student_module_list_path(#student)
For the second option, you can just remove :new from the before_action, change the new method to
def new
#module_list = ModuleList.new
end
And then add a way of picking which student to tie it to to the form.
I would like users to be able to create/update my "Person" resource, including overwriting each other. Currently I'm able to capture the user who created the initial "Person" but i can't figure out how to capture and display the user that updated the resource.
For example if user 1 creates an item, then user 2 updates this item, I would like to display that this item was most recently edited by user 2.
Here's my controller, any help would be much appreciated thanks!
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = current_user.person.build
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create
#person = current_user.person.build(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render action: 'show', status: :created, location: #person }
else
format.html { render action: 'new' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:name, :twitter, :facebook, :instagram, :vine)
end
end
Simple way for doing it is to maintain the a column called updated_by and store the current user when its updated as #Andrey mentioned in previous comment.
But if your looking for a more extensive for tracking you can use auditable gem
You can check this out :
https://github.com/harley/auditable
Create updated_by column in posts table, and each time user updates the post, update the column updated_by by the value of current_user.
Can I disable the "Edit" and "Destory" in the Rails ?for example, if I want to disable the "Edit" for everyone,what show I do in the test_controller.rb ? or anything else?
I am new to Rails, thanks in advance!
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update,:destroy ]
# GET /books
# GET /books.json
def index
#books = Book.all
end
# GET /books/1
# GET /books/1.json
def show
end
# GET /books/new
def new
#book = Book.new
end
# GET /books/1/edit
def edit
end
# POST /books
# POST /books.json
def create
#book = Book.new(book_params)
respond_to do |format|
if #book.save
format.html { redirect_to #book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: #book }
else
format.html { render :new }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /books/1
# PATCH/PUT /books/1.json
def update
respond_to do |format|
if #book.update(book_params)
format.html { redirect_to #book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: #book }
else
format.html { render :edit }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.json
def destroy
#book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
#book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:name, :author, :price)
end
end
`Rails.application.routes.draw do
resources :books
root :to => "home#index"
get 'home/index'
end`
You can restrict the restful routes to make edit and destroy actions inaccessible.
In your routes.rb,
resources :books, except: [:edit, :destroy]
See: http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
EDIT
If you want to keep to the RESTful routes (so that you don't have to modify code in your views), you can use before_action in controller to redirect users.
before_action :redirect_user, only: [:edit,:destroy]
def redirect_user
redirect_to root_path
end
This approach is generally used when you want to restrict access to certain actions based on some condition.
For example, if you want only admins to edit and remove books, you can have condition inside redirect_user that checks if current user is admin or not and redirects non-admin users.
You should look in to the cancancan gem.
https://github.com/CanCanCommunity/cancancan
It's an authorization library for Ruby on Rails which restricts what resources a given user is allowed to access. So you can create an admin class, and only allow administrators to edit and destroy. Its pretty simple to use and works well with devise.
I have an ApplicationController with a given method in the public area
def current_user
session[:user]
end
and another controller
ObjetosController < ApplicationController
which needs to access such method, and I'm getting a horrible error while running my tests (rake test:functionals):
NameError: undefined local variable or method `current_user' for
I'm using Ruby 2.0.0 and Rails 4.0. I've been travelling Google and StackOverflow for hours and hours and haven't found anything about it.
Maybe someone can give me a hint or help me search for an answer please?
If it helps, if I put crap inside ApplicationController, and run the test, it doesn't complain!!! It's like it was loading another version of this class...
Here my ObjetosController code:
class ObjetosController < ApplicationController
before_action :set_objeto, only: [:show, :edit, :update, :destroy]
# GET /objetos
# GET /objetos.json
def index
#objetos = Objeto.all
end
# GET /objetos/1
# GET /objetos/1.json
def show
end
# GET /objetos/new
def new
#objeto = Objeto.new
end
# GET /objetos/1/edit
def edit
end
# POST /objetos
# POST /objetos.json
def create
#objeto = Objeto.new(objeto_params)
respond_to do |format|
if #objeto.save
format.html { redirect_to #objeto, notice: 'Objeto was successfully created.' }
format.json { render action: 'show', status: :created, location: #objeto }
else
format.html { render action: 'new' }
format.json { render json: #objeto.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /objetos/1
# PATCH/PUT /objetos/1.json
def update
current_user
respond_to do |format|
if #objeto.update(objeto_params)
format.html { redirect_to #objeto, notice: 'Objeto was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #objeto.errors, status: :unprocessable_entity }
end
end
end
# DELETE /objetos/1
# DELETE /objetos/1.json
def destroy
#objeto.destroy
respond_to do |format|
format.html { redirect_to objetos_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_objeto
#objeto = Objeto.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def objeto_params
params.require(:objeto).permit(:nombre, :codigo_sgej)
end
end
Solved it.
In my ApplicationController class I was instantiating some classes dynamically defined for each environment. I was also using some constants defined per environment.
As this app hasn't been released to staging or production yet, I had such values defined only in config/environments/development.rb file. I added them to config/environments/test.rb and now it works!
I lost hours with this problem, I'm really dissapointed with rails (or ruby?) for not showing any error at all...
Okay guys, I am fairly new to rails. I have successfully created a rails app that stores login information for you. I used devise for the user management and installed cancan but no idea how to use it.
Anyways,
Right now, not matter if you are logged in or not, the site shows you all the "post" or "entrees" that have been entered by any user. I need a way to restrict this to only show post that were made by the user that is currently logged in.
I have found through research that I need do something here:
class FtpLoginsController < ApplicationController
before_action :set_ftp_login, only: [:show, :edit, :update, :destroy]
# GET /ftp_logins
# GET /ftp_logins.json
def index
#ftp_logins = FtpLogin.all
end
# GET /ftp_logins/1
# GET /ftp_logins/1.json
def show
end
# GET /ftp_logins/new
def new
#ftp_login = FtpLogin.new
end
# GET /ftp_logins/1/edit
def edit
end
# POST /ftp_logins
# POST /ftp_logins.json
def create
#ftp_login = FtpLogin.new(ftp_login_params)
respond_to do |format|
if #ftp_login.save
format.html { redirect_to #ftp_login, notice: 'Ftp login was successfully created.' }
format.json { render action: 'show', status: :created, location: #ftp_login }
else
format.html { render action: 'new' }
format.json { render json: #ftp_login.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ftp_logins/1
# PATCH/PUT /ftp_logins/1.json
def update
respond_to do |format|
if #ftp_login.update(ftp_login_params)
format.html { redirect_to #ftp_login, notice: 'Ftp login was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #ftp_login.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ftp_logins/1
# DELETE /ftp_logins/1.json
def destroy
#ftp_login.destroy
respond_to do |format|
format.html { redirect_to ftp_logins_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ftp_login
#ftp_login = FtpLogin.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ftp_login_params
params.require(:ftp_login).permit(:client_name, :website_name, :ftp_login, :ftp_password, :notes)
end
end
If someone could please send me in the right direction here that would be fantastic!
Thanks in advance.
for that you first have to make ensure that user is logged in before it goes to your action . so you need a before filter for that . authenticate_user! is a method given by devise . so if a user is not logged in he will redirect to the sign in page automatically
before_filter :authenticate_user!, only: [:posts, :entries]
for collecting the posts of a specific user
#posts = current_user.posts
or if it is coming for show a particular post you can do
#post = current_user.posts.where(id: params[:id])
You can use before_filter :authenticate_user!, only: [:posts, :entries] to restrict only the logged in user to view these actions.
To restrict users to view only posts created by them, you can create your own filter like
def check_user
redircet_to :back, notice: "Restricted area!" if current_user.posts.include?(#post)
end