I'm trying to build a blog using rails in c9 ubuntu setup. While I was optimizing routes, I realized that my url in browser does not change along with my actions, though everything works just fine.
The url that can be seen in the browser is actually set to display all the blogs' posts, and it does, but when I try to click on only one (in this case 'My Blog Post 1') it performs the action, but url remains the same.
However, if I type the correct url manually, it also works.
Everything is working, but my url doesn't change automatically, but I have to do it manually. In this stage I can handle that, but I'm afraid I'll have problems with that later on. This is my first time that I use cloud9 environment.
Controller:
class BlogsController < ApplicationController
before_action :set_blog, only: [:show, :edit, :update, :destroy]
# GET /blogs
# GET /blogs.json
def index
#blogs = Blog.all
end
# GET /blogs/1
# GET /blogs/1.json
def show
end
# GET /blogs/new
def new
#blog = Blog.new
end
# GET /blogs/1/edit
def edit
end
# POST /blogs
# POST /blogs.json
def create
#blog = Blog.new(blog_params)
respond_to do |format|
if #blog.save
format.html { redirect_to #blog, notice: 'Blog was successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /blogs/1
# PATCH/PUT /blogs/1.json
def update
respond_to do |format|
if #blog.update(blog_params)
format.html { redirect_to #blog, notice: 'Blog was successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /blogs/1
# DELETE /blogs/1.json
def destroy
#blog.destroy
respond_to do |format|
format.html { redirect_to blogs_url, notice: 'Blog was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_blog
#blog = Blog.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def blog_params
params.require(:blog).permit(:title, :body)
end
end
Routes:
Rails.application.routes.draw do
resources :portofolioos, except: [:show]
get 'portofolioo/:id', to: 'portofolioos#show', as: 'portofolioo_show'
get 'about', to: 'pages#about'
get 'contact', to: 'pages#contact'
resources :blogs
root to: 'pages#home'
end
View just has a form. It's pretty much scaffold, I only changed show page to display id in url and added friendly_id gem, but none of it is displayed in url, but it works just fine.
<p><%= link_to portofolio_item.title, portofolioo_show_path(portofolio_item) %></p>
Related
I'm having issues with routing a rails app to use a new and edit form.
The routes use the username within the URL.
lists GET /lists(.:format) lists#index
POST /user/:username/lists(.:format) lists#create
new_list GET /user/:username/lists/new(.:format) lists#new
edit_list GET /user/:username/lists/:id/edit(.:format) lists#edit
list GET /user/:username/lists/:id(.:format) lists#show
PATCH /user/:username/lists/:id(.:format) lists#update
PUT /user/:username/lists/:id(.:format) lists#update
DELETE /user/:username/lists/:id(.:format) lists#destroy
root GET / static#welcome
show_user GET /user/:id(.:format) users#show
My routes.rb-
get 'lists', to: 'lists#index', as: :lists, via: 'get'
scope 'user/:username' do
resources :lists, except: [:index]
end
My shared form, for use with updating and creating-
<%= form_for [#user, #list], url: list_path(#user, #list) do |f| %>
Using the above settings, I can edit lists correctly, but if I navigate to lists#new, I get the following error-
No route matches {:action=>"show", :controller=>"lists", :id=>nil, :username=>"test"} missing required keys: [:id]
If I pluralize the path in my form to be url: lists_path(#user, #list), then the new page will now load, but when trying to create I get the below error-
No route matches [POST] "/lists.test"
How can I fix these routes so I can use the same shared form for both edits and creating?
Adding controller code-
class ListsController < ApplicationController
before_action :set_list, only: [:show, :edit, :update, :destroy]
def index
#lists = List.all
end
def show
end
# GET /lists/new
def new
#list = List.new
#user = User.find_by(username: params[:username])
end
def edit
#user = User.find_by(username: params[:username])
end
def create
#list = current_user.lists.new(list_params)
respond_to do |format|
if #list.save
format.html { redirect_to list_path(#list.user.username, #list.id), notice: 'List was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #list.update(list_params)
format.html { redirect_to list_path(#list.user.username, #list.id), notice: 'List was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
#list.destroy
respond_to do |format|
format.html { redirect_to lists_url, notice: 'List was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_list
#list = List.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def list_params
params.require(:list).permit(:name, :category, :user_id)
end
end
Try this - Change the :url value in the form_for to [[#list], :username => #user.username]
Like so:
<%= form_for [#user, #list], url: [[#list], :username => #user.username] do |f| %>
I searched about this question, but had no success.
I´m trying to learn ruby on rails, came from php. I generated a webapp with the generation tool, second I generated a News controller with scaffold. The devise and pundit are installed too with gems.
The program works perfectly, the problem is related to the News module, I generated it with scaffold.
The routes where created with the command: resources :news
My idea is to create one _form.html.erb and it be called to create a new record or to updated an existing record. Some tutorials teach to create a new.html.erb and an update.html.erb file and duplicate the code, but I know that is possible to have partials as the main form part.
I´m using simple_form_for and the code to do the new is:
# GET /news/new
def new
#news = New.new
authorize New
end
The _form.html.erb
<%= simple_form_for(#news) do |f| %>
<%= f.input :titulo %>
<%= f.input :resumo %>
<%= f.button :submit %>
<% end %>
When I enter to edit, it works, but to add a new it throws.
ActionController::UrlGenerationError at /news/new
No route matches {:action=>"show", :controller=>"news", :locale=>:en} missing required keys: [:id]
Sorry for my bad english, I´m without direction here, is there any way that I can solve it?
Thanks.
====== UPDATED =======
routes.rb
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users
resources :news
end
New.rb (Model)
class New < ActiveRecord::Base
belongs_to :user
end
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :set_locale
def default_url_options(options={})
{ locale: I18n.locale }
end
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
news_controller.rb (Complete)
class NewsController < ApplicationController
before_filter :authenticate_user!
after_action :verify_authorized
#before_action :set_news, only: [:show, :edit, :update, :destroy]
# GET /news
# GET /news.json
def index
#news = New.all
authorize New
end
# GET /news/1
# GET /news/1.json
def show
#news = New.find(params[:id])
authorize New
end
# GET /news/new
def new
#news = New.new
authorize New
end
# GET /news/1/edit
def edit
#news = New.find(params[:id])
authorize New
end
# POST /news
# POST /news.json
def create
#news = New.new(news_params)
respond_to do |format|
if #news.save
format.html { redirect_to #news, notice: 'New was successfully created.' }
format.json { render :show, status: :created, location: #news }
else
format.html { render :new }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /news/1
# PATCH/PUT /news/1.json
def update
respond_to do |format|
if #news.update(news_params)
format.html { redirect_to #news, notice: 'New was successfully updated.' }
format.json { render :show, status: :ok, location: #news }
else
format.html { render :edit }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# DELETE /news/1
# DELETE /news/1.json
def destroy
#news.destroy
respond_to do |format|
format.html { redirect_to news_url, notice: 'New was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_news
#news = New.find(params[:id])
end
private
def news_params
params.require(:news).permit(:titulo, :resumo, :texto, :published_at, :user_id)
end
end
Command rake routes
news_index GET /news(.:format) news#index
POST /news(.:format) news#create
new_news GET /news/new(.:format) news#new
edit_news GET /news/:id/edit(.:format) news#edit
news GET /news/:id(.:format) news#show
PATCH /news/:id(.:format) news#update
PUT /news/:id(.:format) news#update
DELETE /news/:id(.:format) news#destroy
Thanks in advance.
======= UPDATE 2 ===========
Changing my New action to this:
def new
#news = New.create(params[:id])
end
It solved, but everytime I enter, it creates an empty record...
Use news_index_path for GET /news and POST /news. Rails doesn't figure out the pluralization correctly for the "news" term.
Check the output of rake routes, it will be obvious.
I get the following error, Couldn't find User with 'id'=
I have this in my Users_Controller,
def edit
#user = #signed_in_user
end
This is in my routes.rb,
root 'welcome#welcome'
get 'login' => 'sessions#login', :as => :login
get 'profile' => 'users#profile', :as => :profile
post 'logging/user' => 'sessions#create'
get 'logout' => 'sessions#destroy', :as => :logout
get 'about' => 'about'
resources :users
get 'register' => 'users#new', :as => :register
get 'edit' => 'users#edit', :as => :edit
This is in my application_controller.rb,
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :set_user
protected
def set_user
unless session[:user_id] == nil
#signed_in_user = User.find(session[:user_id])
end
end
end
This is in my Users_Controller
Here is my code from my User_Controller on creating the account
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
def profile
#user = User.find(session[:user_id]) unless session[:user_id] == ""
redirect_to login_path, notice: "You're not logged in" unless #user
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
#user = #signed_in_user
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :password, :password_confirmation, :email, :age)
end
end
And this is the link that I use for my HTML,
<li role="presentation"><%= link_to 'Edit', edit_path %></li>
So, to start, a good practice when you get an 'Couldn't find' message is to check what instance variables are in your view.
So in a view, just type: <%= #user_id %> and see if anything shows up on your page, thus indicating if any user is even present! The other problem is that your instance variable might be <%= user.id %> but I am not sure as I can't see your code and how the user is stored in the database.
Second if you run rake routes, you generally find that the edit path will have a URI pattern like: "/edit(.:format)", meaning the route need "edit_path(#user.id)" rather than just "edit_path".
Let me know if this leads you anywhere or you have further questions and I hope I can answer them!
===========
Additional info:
Well without more code to look at, I would provide a few more suggestions...The goal is to have the <%= #user.id %> (or user_id) show up on the page somehow, thus telling you it is available.
The set_user method is an instance method, not a class method. To make it a class method, try def self.set_user. This invokes the method of the instance on the controller, thus making it a class method.
Make sure you have a session object to use. In the routes, it looks like post logging/user might be creating the session, but I am not sure.
Keep the edit_path(#user.id) or however the id is stored for the user as the route rather than just edit_path. I am pretty sure if you run 'rake routes', it will tell you that an additional variable needs to be passed for the link to work
Use the gem byebug Here is the link: https://github.com/deivid-rodriguez/byebug. You get this error while the edit page or where ever you are getting the error write in the action byebug. As you have mentioned in the console it shows a arrow pointing at a specific line in the application, the last line should appear as this (byebug), here write the variable in which you are getting the user id. If we take an example of your application controller in the set_user method:
def set_user
byebug
unless session[:user_id] == nil
#signed_in_user = User.find(session[:user_id])
end
end
In the console after (byebug) write session[:user_id] so this will give you the value of the session[:user_id]. So if this is null then you have a problem here or just follow the same procedure to check anywhere else.
Also there is one more thing you can do to learn is just create a new project or use the existing one and generate a scaffold which will give you options of show, edit, index. It will generate all the views, controller code, migration and everything. You can do that like this:
rails generate scaffold User email:string password:string
You can add more fields if you want. And then in your application just visit http://localhost:[port_no]/users which will by default take you to index page where you can add new users, edit existing ones. This will teach you about everything. It would be like a reference code for you. Read more at: http://guides.rubyonrails.org/command_line.html#rails-generate
And being more specific to users only there is a gem named Devise which will give you all the required things like sign_in, sign_up, session_management for users. Hope these things help you with your issue.
Edit:
Here is a very good tutorial link which will help you: https://www.railstutorial.org/book/updating_and_deleting_users#sec-updating_users
I am coding a Ruby on Rails app (rails 4), on an ubuntu machine.
I have created a new scaffold (model/view/controller) via rails g scaffold common_warnings , and it works just fine on my local machine (localhost:3000/common_warnings resolves to something appropriate), however when I upload this to my server, I get this error:
ActionController::RoutingError (uninitialized constant CommonWarningsController)
when trying to get mydomain.com/common_warnings.
I know that sometimes pluralization is a problem, these are the first lines of each of my controller and model files:
app/controllers/common_warnings_controller.rb
class CommonWarningsController < ApplicationController
app/models/common_warning.rb
class CommonWarning < ActiveRecord::Base
My rails app already has 30something tables in the database, I know I did have this problem a while ago but just can't work out how to fix this one. The pluralization seems to match what I do for loan_histories_controller.rb (also a multi-word name).
The output of rake routes is the same on my local machine and on the server. This is the relevant output:
rake routes | grep common
common_warnings GET /common_warnings(.:format) common_warnings#index
POST /common_warnings(.:format) common_warnings#create
new_common_warning GET /common_warnings/new(.:format) common_warnings#new
edit_common_warning GET /common_warnings/:id/edit(.:format) common_warnings#edit
common_warning GET /common_warnings/:id(.:format) common_warnings#show
PATCH /common_warnings/:id(.:format) common_warnings#update
PUT /common_warnings/:id(.:format) common_warnings#update
DELETE /common_warnings/:id(.:format) common_warnings#destroy
"The server" in this case is provided by AWS
This is my complete common warnings controller:
class CommonWarningsController < ApplicationController
before_action :set_common_warning, only: [:show, :edit, :update, :destroy]
before_action :signed_in_user
before_action :admin_user
# GET /common_warnings
# GET /common_warnings.json
def index
#common_warnings = CommonWarning.all
end
# GET /common_warnings/1
# GET /common_warnings/1.json
def show
end
# GET /common_warnings/new
def new
#new_or_edit = 'new'
#common_warning = CommonWarning.new
end
# GET /common_warnings/1/edit
def edit
#new_or_edit = 'edit'
end
# POST /common_warnings
# POST /common_warnings.json
def create
#common_warning = CommonWarning.new(common_warning_params)
respond_to do |format|
if #common_warning.save
format.html { redirect_to #common_warning, notice: 'Common warning was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
# PATCH/PUT /common_warnings/1
# PATCH/PUT /common_warnings/1.json
def update
respond_to do |format|
if #common_warning.update(common_warning_params)
format.html { redirect_to #common_warning, notice: 'Common warning was successfully updated.' }
else
format.html { render action: 'edit' }
end
end
end
# DELETE /common_warnings/1
# DELETE /common_warnings/1.json
def destroy
#common_warning.destroy
respond_to do |format|
format.html { redirect_to common_warnings_url }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_common_warning
#common_warning = CommonWarning.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def common_warning_params
params.require(:common_warning).permit(:name)
end
def signed_in_user
store_location
redirect_to signin_url, notice: "Please sign in." unless signed_in?
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
Thanks in advance!
Fixed. It was a complicated problem to do with having multiple similar but not identical rails apps running from one server. I had forgotten to reset the connection to the schema migrations. Thanks to those who responded!
So I had my app set up with ids like so:
resources :studios do
resources :bookings
end
This gave me the route to the index (which later I'm going to use json for to get calendars for each studio.
studio_bookings GET /studios/:studio_id/bookings(.:format) bookings#index
This is good, but I wanted to get rid of the ID and use a permalink instead, just for a friendlier URL.
Change to:
namespace :studio, :path =>'/:permalink' do
resources :bookings
end
Now I'm getting
studio_bookings GET /:permalink/bookings(.:format) studio/bookings#index
Great! this is how I want my url to look, however, now the :id isn't anywhere in the route so... I get
Couldn't find Booking without an ID
It isn't even being passed. Is there a way to pass the :id in with the url without it being actually USED in the url? Otherwise, do I change the primary key from :id to :permalink in order to fix this?
I tried changing my controller from
#studio = Studio.find(params[:id])
to
#studio = Studio.find(params[:permalink])
but that gives me
Couldn't find Booking with 'id'=40frost
Which tells me what I'm doing isn't really meant to be done? It's trying to put the permalink as the id, so even though I'm telling rails to look for the permalink, it's still seemingly looking it up as an ID.
Hopefully my problem is clear: essentially - how can I pass the id so it knows which studio without displaying it in the URL. If there's some controller magic I can do instead that would be convenient.
Here's my controller for good measure
class Studio::BookingsController < ApplicationController
before_action :set_booking, only: [:show, :edit, :update, :destroy]
# GET /bookings
# GET /bookings.json
def index
#studio = Studio.find(params[:permalink])
#bookings = Booking.where("studio_id => '#studio.id'")
end
# GET /bookings/1
# GET /bookings/1.json
def show
end
# GET /bookings/new
def new
#booking = Booking.new
end
# GET /bookings/1/edit
def edit
end
# POST /bookings
# POST /bookings.json
def create
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, notice: 'Booking was successfully created.' }
format.json { render action: 'show', status: :created, location: #booking }
else
format.html { render action: 'new' }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /bookings/1
# PATCH/PUT /bookings/1.json
def update
respond_to do |format|
if #booking.update(booking_params)
format.html { redirect_to #booking, notice: 'Booking was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
# DELETE /bookings/1
# DELETE /bookings/1.json
def destroy
#booking.destroy
respond_to do |format|
format.html { redirect_to bookings_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_booking
#booking = Booking.find(params[:permalink])
end
# Never trust parameters from the scary internet, only allow the white list through.
def booking_params
params.require(:booking).permit(:start_time, :end_time, :studio_id, :engineer_id, :title, :allDay)
end
end
You could just do
self.primary_key = 'permalink'
in your Studio model, or you could do
def index
#studio = Studio.find_by permalink: params[:permalink]
#bookings = Booking.where(studio_id: #studio.id)
end
depends if you just want to locally change the behavior or adress the Studio model by permalink always.
Hope that helps!