I have a controller:
controller/streets_controller.rb
class StreetsController < ApplicationController
before_action :set_street, only: [:show, :edit, :update, :destroy]
def show
#house = #street.houses.build
end
.......
And a view for that show action. There I also display a form to create new street houses:
views/streets/show.html.erb
<h1>Street</h1>
<p>#street.name</p>
<%= render '/houses/form', house: #house %>
When somebody submits the houses/form the request goes to the houses_controller.rb
class HousesController < ApplicationController
def create
#house = House.new(house_params)
respond_to do |format|
if #house.save
format.html { redirect_back(fallback_location: streets_path) }
format.json { render :show, status: :created, location: #house }
else
format.html { redirect_back(fallback_location: streets_path) }
format.json { render json: #house.errors, status: :unprocessable_entity }
end
end
end
So far it works that when somebody inserts correct house_params it redirects back and creates the house correctly
But when somebody inserts wrong house_params it redirects_back but it doesn't show the house errors in the form, it shows the form for a new house #house = #street.houses.build
How can I redirect to the StreetsController with the #house object, so that the errors are shown and also the house form is filled?
Thanks
Generally when there is an error in the create action, you would render the "new" view instead of redirecting back. In your case, you could try redirecting to the streets show path, and passing the #house attributes as query params. Then in StreetsController#show, pass the house params as an argument to build.
Related
I am a newbie in RoR, thus sorry for stupid question :(
I have a Game model, with a code string. There is a welcome/index view in my app with a simple form_to input. I wish to redirect user to a Game with a specific code after he submits the form.
I understand that I should somehow combine a .where method and redirect_to in Welcome_controller, but I just can't figure out how...
Welcome_controller.rb:
class WelcomeController < ApplicationController
def index
end
def redirect
redirect_to ?game with a code that equals :param from input?
end
end
Welcome/index:
<h1>Let's join the game!</h1>
<%= form_tag redirect_path do %>
<%= text_field_tag(:param) %>
<%= submit_tag("Search") %>
<% end %>
routes.rb:
Rails.application.routes.draw do
get 'welcome/index'
resources :games
get 'games/index'
root 'welcome#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
game.rb:
class Game < ApplicationRecord
validates :name, :presence => true
end
games_controller:
PREFACE = ('A'..'Z').to_a << ?_
SUFFIX = ('0'..'9').to_a
PREFACE_SIZE = 2
SUFFIX_SIZE = 3
class GamesController < ApplicationController
before_action :set_game, only: %i[ show edit update destroy ]
# GET /games or /games.json
def index
#games = Game.all
end
# GET /games/1 or /games/1.json
def show
end
# GET /games/new
def new
#game = Game.new
#game.code = gen_name
end
def gen_name
PREFACE.sample(PREFACE_SIZE).join << SUFFIX.sample(SUFFIX_SIZE).join
end
# GET /games/1/edit
def edit
end
# POST /games or /games.json
def create
#game = Game.new(game_params)
respond_to do |format|
if #game.save
format.html { redirect_to game_url(#game), notice: "Game was successfully created." }
format.json { render :show, status: :created, location: #game }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /games/1 or /games/1.json
def update
respond_to do |format|
if #game.update(game_params)
format.html { redirect_to game_url(#game), notice: "Game was successfully updated." }
format.json { render :show, status: :ok, location: #game }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
# DELETE /games/1 or /games/1.json
def destroy
#game.destroy
respond_to do |format|
format.html { redirect_to games_url, notice: "Game was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_game
#game = Game.find(params[:id])
end
# Only allow a list of trusted parameters through.
def game_params
params.require(:game).permit(:code, :name)
end
end
In config/routes.rb you have defined resources :games, which creates default paths for CRUD actions. For the show action, which you are trying to get here, it would lead to /games/:id and the helper method would be game_path. You can also check this by running rails routes -c games command in the app directory. It should return all paths for games_controller
In the before_action callback for GamesController#show action, you are finding a Game object using Game.find(params[:id]). :id parameter is what you need to pass to the path helper that I mentioned earlier for the action to fire properly, so the path to a specific game would look like game_path(id: game.id). This will then automatically get converted to params. Alternatively, you can just pass the game object to the path helper and it will do the job for you like this: game_path(game)
Now in the WelcomeController#redirect action, you get the game code in params from the form submit. You need to first find the game for the submitted code like this:
game = Game.find_by(code: params[:param])
This should work if the code is unique for each game. Now that you have the correct game record, all you need is to redirect to the path that I've mentioned eariler:
redirect_to game_path(game)
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 have been stuck on this problem for a while now and have searched through solution after solution and so far, the ones i have come across do not work.
i made a new rails scaffold for a new Object for my application, i have the table set up and i can view the Post objects when i run the server.
The problem when i go to view the Post objects when my server is running, it's content does not display, and i cannot update the objects this error gets thrown:
param is missing or the value is empty: post
The Posts table in the database looks like this:
posts table
As you can see, the field content has data that i want to display on my page when i go to view said Post.
This is what comes up instead:
what i see when running the server
AS you can see, it wont display the content of the content field.
This is my posts_controller.rb
class PostsController < ApplicationController
# you may want to udpate these posts? typo's outdated info?
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 action: 'show', status: :created, location: #post }
else
format.html { render action: '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 { head :no_content }
else
format.html { render action: '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 }
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(:content)
end
end
i thought this would allow me to see the content
def post_params
params.require(:post).permit(:content)
end
And i thought this is what defines:post because of before_action :set_post, only: [:show, :edit, :update, :destroy]
def set_post
#post = Post.find(params[:id])
end
This is what is shown on the error page in rails:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"tHFQAWv08aUoi7ndZsVC1aCNJkYP6hE8w+89NTTpBjc=",
"commit"=>"Update Post",
"id"=>"2"}
I am really confused to why this is happening, im new to rails so no doubt im missing something basic.
Thanks,
Chris.
Your request is missing the post param:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"tHFQAWv08aUoi7ndZsVC1aCNJkYP6hE8w+89NTTpBjc=",
"commit"=>"Update Post",
"id"=>"2"}
This is most likely due to an error in the form in your app/views/posts/edit.html.erb view. The form should look something like this:
<%= form_for #post, url: {action: "edit"} do |f| %>
<%= f.text_area :content %>
<%= end %>
You can read more about forms in the rails guides.
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