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.
Related
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
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 am new to rails I created post model and posts_controller which has Name:string, EMail:string, Message:text, topic_id:integer columns using scaffold.
I also created a topic model and topics_controller which has Topic_Name:string in it.
I provided the relationship among the models as follows:
class Topic < ActiveRecord::Base
has_many :posts, foreign_key: 'topic_id'
end
class Post < ActiveRecord::Base
belongs_to :topic
end
In routes.db I created the nested resources as:
resources :topics do
resources :posts
end
topics_controller.rb code:
class TopicsController < ApplicationController
before_action :set_topic, only: [:show, :edit, :update, :destroy]
# GET /topics
# GET /topics.json
def index
#topics = Topic.all
end
# GET /topics/1
# GET /topics/1.json
def show
end
# GET /topics/new
def new
#topic = Topic.new
end
# GET /topics/1/edit
def edit
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(topic_params)
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render :show, status: :created, location: #topic }
else
format.html { render :new }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /topics/1
# PATCH/PUT /topics/1.json
def update
respond_to do |format|
if #topic.update(topic_params)
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { render :show, status: :ok, location: #topic }
else
format.html { render :edit }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url, notice: 'Topic was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_topic
#topic = Topic.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def topic_params
params.require(:topic).permit(:Name)
end
end
posts_controller code:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:Name, :Email, :Message, :topic_id)
end
end
I need to group posts using the topic. i.e., On clicking show on a particular topic it should go to the URL /topics/<topic_id>/posts where it should lists all posts related to that topic and I can create/delete posts belongs to that topic.
Can anyone help doing this..
Thank you..
Your question should be more direct, there's a lot of information that aren't related to the problem (the attributes names, for example), and your goal isn't clear enough.
It seems that you just want to setup the routes, right? You already have all posts related to that topic though the association: topic.posts. You just need to setup nested resource routes for posts:
resources :topics do
resources :posts
end
Also, you don't need the foreign_key option since you're using the naming conventions. It seems as well that you named some attributes in upper case, they should be name, email and message.
UPDATE:
In the index action, since you want posts belonging to one topic, you need to scope the #posts instance variable. Since you're using nested resources, you have the parameter params[:topic_id], so just fetch the topic with #topic = Topic.find(params[:topic_id]), then scope the association with #posts = #topic.posts. You'll need to do the same for every other action. I recommend that you read a little about associations in Rails, you'll probably need to use methods like #topic.posts.build and #topic.posts.find(params[:id]).
I found the solution for this problem in this link: Nested resources
Download the source code and find the solution...
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.
After performing a rails g scaffold Project name:string, I get a routing error when I create a new project.
My steps:
1) on /projects, I click 'New Project'.
2) I fill the project details and click 'Create Project'.
In this step the form seems to be correct:
form accept-charset="UTF-8" action="/projects" class="new_project" id="new_project" method="post"
3) I get the following error (routing error): No route matches [POST] "/projects/new"
Whereas:
when I reload the /projects/new page, the creation of the project works fine
Any reason for this?
Below are the files I have (I created most of them with the scaffolding)
app/models/project.rb:
class Project < ActiveRecord::Base
end
app/controllers/projects_controller.rb: (I only show here the methods that we re interested in)
class ProjectsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
before_action :set_project, only: [:show, :edit, :update, :destroy]
# GET /projects/new
def new
#project = Project.new
end
# GET /projects/1/edit
def edit
end
# POST /projects
# POST /projects.json
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render action: 'show', status: :created, location: #project }
else
format.html { render action: 'new' }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /projects/1
# PATCH/PUT /projects/1.json
def update
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_project
#project = Project.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:name)
end
end
and config/routes.rb:
Testproject::Application.routes.draw do
devise_for :users
resources :projects
root 'projects#index'
end
Thanks for your help