NoMethodError (undefined method `product_url' - ruby-on-rails

I have the following error when debugging my first project on rails:
NoMethodError (undefined method `product_url' for #
Did you mean? products_url):
app/controllers/products_controller.rb:13:in `create'
class ProductsController < ApplicationController
def show
#product = Product.find(params[:id])
end
def new
end
def create
#product = Product.new(product_params)
#product.save
redirect_to #product
end
private
def product_params
params.require(:product).permit(:title, :price, :count)
end
end
----------config/routes.rb------
Rails.application.routes.draw do
get 'welcome/index'
resource :products
root 'welcome#index'
end
----------rake routes----------
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
new_products GET /products/new(.:format) products#new
edit_products GET /products/edit(.:format) products#edit
products GET /products(.:format) products#show
PATCH /products(.:format) products#update
PUT /products(.:format) products#update
DELETE /products(.:format) products#destroy
POST /products(.:format)

You need to initialise #product. It can be done like:
before_action :set_document, only: [:show, :edit, :update, :destroy]
def set_document
#document = Document.find(params[:id])
end
You can scaffold the Controller with
rails g scaffold_controller Document
to see exactly how rails is generating classes for a model.
In your routes.rb it should be
resources: products

Related

ROR Form_with keeps giving me a NoMethodError

I'm sure this should be a simple issue, but can't find a solution (im new to ROR).
This is the error im getting:
-----error------
NoMethodError in Agency::Clientmanagement#edit
Showing /home/ubuntu/environment/nacho/app/views/agency/clientmanagement/_form_client.html.erb where line #2 raised:
undefined method `client_path' for #ActionView::Base:0x007fcda8bd7ae0
Did you mean? clients_path
<%= form_with model: #clientrecord do |f| %>
------ This is my routes------
root 'pages#home'
get 'clients', to: 'clients#index'
get 'agency', to: 'agency#index'
get 'admin', to: 'admin#index'
get 'clientview', to: 'agency#clientview'
#post 'clientview', to: 'agency#clientview'
namespace :admin do
get "new", to: 'manager#new'
get "add-user", to: 'manager#add-user'
get "agencies", to: 'manager#agencies'
end
namespace :agency do
resources :clientmanagement, only: [:show,:new, :create, :edit]
resources :team, only: [:index, :show,:new, :create, :edit]
end
-------this is the: admin/clientmanagementcontroller
class Agency::ClientmanagementController < ApplicationController
before_action :require_agencyaccount
before_action :user_clients
before_action :set_client, only: [:show]
# before_action :set_one_product, only: [:show]
# def index
# #all_shoe_products = #all_products.where(main_category_id: MainCategory.find_by_name("shoes").id)
# end
def show
end
def new
end
def create
end
def edit
#clientrecord = Client.find(params[:id])
end
private
def user_clients
#clients = User.find(current_user.id).clients
end
def set_client
#client = Client.find(params[:id])
end
--- here is the form_with in the form partial being rendered in /agency/clientmanagement/{id}/edit
<%= form_with model: #clientrecord do |f| %>
Any help would be greatly appreciated
In your routes.rb file I don't see client_path is defined.
Option 1: You can add client path by adding the following route below clients path:
Rails.application.routes.draw do
get 'clients', to: 'clients#index'
get 'client', to: 'clients#show'
...
end
this will generate the following path:
client_path GET /client(.:format) clients#show
Option 2: If you have a full resource controller for clients, you can add
resources :clients
this will generate all RESTful routes for clients
clients_path GET /clients(.:format) clients#index
POST /clients(.:format) clients#create
new_client_path GET /clients/new(.:format) clients#new
edit_client_path GET /clients/:id/edit(.:format) clients#edit
client_path GET /clients/:id(.:format) clients#show
PATCH /clients/:id(.:format) clients#update
PUT /clients/:id(.:format) clients#update
DELETE /clients/:id(.:format) clients#destroy

How to define routes that include a dynamic organization name in Rails

I'm building a Rails 5.2 SaaS application that allows users to belong to many "organizations". Users will only see content for their currently active organization.
I started down the path of using subdomains, but after a little more research have decided to avoid them for now.
My new approach (to make it explicit to the user what organization they are using, support sharing links, browser history etc..) is to embed the organization name in the path. For example:
https://app.example.com/foo/posts # Posts for org "foo"
https://app.example.com/foo/posts/7 # Post for org "foo"
https://app.example.com/bar/posts # Posts for org "bar"
https://app.example.com/settings # General account settings
https://app.example.com/signin # Sign in
My problem is how to do this with Rails routes? I've tried to use a dynamic scope:
scope ':org' do
resources :posts
end
Results in errors like:
No route matches {:action=>"show", :controller=>"posts", :org=>#<Organization id: 1, name: "My Organization", ...}, missing required keys: [:id]
For the code:
# layouts/application.html.erb
<%= link_to post, post, class: 'dropdown-item' %>
Any suggestions on how to configure routes to support this use case?
Use the resources macro:
Rails.application.routes.draw do
resources :posts, except: [:new, :create]
resources :organizations, path: '/', only: [] do
resources :posts, module: :organizations, only: [:new, :index, :create]
end
end
$ rails routes:
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
organization_posts GET /:organization_id/posts(.:format) organizations/posts#index
POST /:organization_id/posts(.:format) organizations/posts#create
new_organization_post GET /:organization_id/posts/new(.:format) organizations/posts#new
By using the module: option you can setup a separate controller for the nested context:
# app/controllers/organizations/posts_controller.rb
class Organizations::PostsController < ApplicationController
before_action :set_organization!
# Index for posts belonging to a specific organization
# GET /:organization_id/posts
def index
#posts = #organization.posts
end
# GET /:organization_id/posts/new
def new
#post = #organization.posts.new
end
# POST /:organization_id/posts
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
private
def set_organization!
#organization = Organization.includes(:posts)
.find_by!(name: params[:organization_id])
end
def post_params
params.require(:post).permit(:title)
end
end
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# Index for posts belonging to all organizations
# GET /posts
def index
#posts = Post.all
end
# GET /posts/1
def show
end
# GET /posts/1/edit
def edit
end
# PATCH/PUT /posts/1
def update
if #post.update(post_params)
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
# DELETE /posts/1
def destroy
#post.destroy
redirect_to posts_url, notice: 'Post was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def post_params
params.require(:post).permit(:title)
end
end
However you should be beware when creating routes that start with a dynamic segment - routes have priority in the order that they are defined and a route that starts with a dynamic segment will be "greedy" and swallow other routes if they are not defined first.

Pretty urls in rails

Im trying to make it work. THis is my rake routes right now:
groups GET /groups(.:format) groups#index
POST /groups(.:format) groups#create
new_group GET /groups/new(.:format) groups#new
edit_group GET /groups/:id/edit(.:format) groups#edit
group GET /groups/:id(.:format) groups#show
PATCH /groups/:id(.:format) groups#update
PUT /groups/:id(.:format) groups#update
DELETE /groups/:id(.:format) groups#destroy
what i want to do is remove "groups" from the link and add slug instead of id.
This is my controller right now:
class GroupsController < ApplicationController
before_action :find_group, only: [:show]
after_action :assign_slug, only: [:create, :update]
def index
#groups = Group.all
end
def show
end
def new
#group = Group.new
end
def create
#group = Group.new(group_params)
if #group.save
flash.notice = "Group has been successfully created!"
redirect_to #group
binding.pry
else
flash.alert = "oops!"
redirect_to action: :new
end
end
private
def group_params
params.require(:group).permit(:title, :description, :country, :city, :category_id)
end
def find_group
#group = Group.find_by_slug(params[:slug])
end
def assign_slug
#group.update(slug: #group.title.parameterize)
end
end
How do i make it work? Thanks.:)
If this is what you want:
routes.rb
get ':slug', to: 'pages#show', as: :groups_show
put ':slug', to: 'pages#update', as: :groups_update
delete ':slug', to: 'pages#destroy', as: :groups_delete
This way the slug will be catched as param and sended to the controller.

redirect_to not working in Posts controller?

For some reason my redirect_to action is no longer working in my Rails 4 app? The error I'm getting is:
Missing template posts/create
Posts Controller
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post
end
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def index
redirect_to root_path
end
private
def post_params
params.require(:post).permit(:content, :community_id, :user_id, :photo, :photo_file_name)
end
Routes
resources :posts do
member do
post :create
end
end
It must not be saving. You can call #post.valid? and #post.errors.full_messages to see any errors or validation issues. Is there a reason why you are building the new post from the current_user? You could also try #post = Post.new(post_params).
Also you don't need to specify create in your routes. Resource routing has create as a default route. See http://guides.rubyonrails.org/routing.html
From what I see when running rake routes
post POST /posts/:id(.:format) posts#create
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
I can see that
post POST /posts/:id(.:format) posts#create
POST /posts(.:format) posts#create
I think this might be the cause of the issues.
I think to make this work you have to remove
member do
post :create
end
from resources :posts
I am not so sure what you are trying to do?
Here, You need to add before_action callback to your controller.
before_action :set_post, only: [:show, :edit, :update, :destroy]
private
def set_post
#post = post.find(params[:id])
end
Now, You will get value for [:show, :edit, :update, :destroy] actions

Inserting variable into routes - map.resources :posts, :as => X - is this possible?

Ok, so I am working on a blog application of sorts. Thus far, it allows for a user to sign up for their own account, create posts, tags, comments, etc.
I have just implemented the ability to use www.myapp.com/brandon to set #user to find by username and therefore correctly display the users information at each url. So when you go to www.myapp.com/brandon you see all Brandon's posts, tags, and comments associated with those posts, etc. Works great.
I'm implementing this URL mapping through the routes.rb file by adding the following:
map.username_link '/:username', :controller => 'posts', :action => 'index'
And then just setting the #user variable in the PostController and corresponding views to find_by_username. Now the issue is this. Once at www.myapp.com/brandon when you click on a post title, it sends to myapp.com/posts/id without the username in the URL.
How do I tell rails to replace the /posts with /username.
Is it even possible to insert the user_username variable into this code?
map.resources :posts, :as => [what goes here]
You said there's going to be more than just posts on the page? comments and tags too? Sounds like we need some resource aggregation here...
Another concern: what if a user picks the name faq and you want domain.com/faq down the road? You can't possibly know all the URLs you will want in the future. Prefixing paths with /profiles is a great way to build a little "namespace" to prevent this from happening. So...
Why not a ProfilesController?
script/generate controller profiles index show
routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :profiles, :only => [:index, :show] do |profile|
profile.resources :posts, :only => [:index, :show]
profile.resources :comments, :only => [:index, :show]
profile.resources :tags, :only => [:index, :show]
end
# ...
end
This will give you the following routes
profiles GET /profiles(.:format) {:controller=>"profiles", :action=>"index"}
profile GET /profiles/:id(.:format) {:controller=>"profiles", :action=>"show"}
profile_posts GET /profiles/:profile_id/posts(.:format) {:controller=>"posts", :action=>"index"}
profile_post GET /profiles/:profile_id/posts/:id(.:format) {:controller=>"posts", :action=>"show"}
profile_comments GET /profiles/:profile_id/comments(.:format) {:controller=>"comments", :action=>"index"}
profile_comment GET /profiles/:profile_id/comments/:id(.:format) {:controller=>"comments", :action=>"show"}
profile_tags GET /profiles/:profile_id/tags(.:format) {:controller=>"tags", :action=>"index"}
profile_tag GET /profiles/:profile_id/tags/:id(.:format) {:controller=>"tags", :action=>"show"}
profiles_controller.rb
class ProfilesController < ApplicationController
# show all profiles; profile browser
# /profiles
def index
end
# show one profile
# /profiles/:id
def show
#user = User.find_by_username(params[:id])
end
end
posts_controller.rb (and others)
class PostsController < ApplicationController
before_filter :find_profile, :only => [:index, :show]
# list all posts for this profile
# /profiles/:profile_id/posts
def index
end
# show one post for this profile
# /profiles/:profile_id/posts/:id
def show
end
protected
def find_profile
#user = User.find_by_username(params[:profile_id])
end
end
You should be able to create the link using:
= link_to "User Posts", subdomain_link_url(#user.username, #post)
In your PostController, then, I would use a before_filter to lookup and set the #user variable:
class PostController < ApplicationController
before_filter :find_user
def other_method
# Some code here
end
protected
def find_user
#user = User.find_by_username(params[:username])
end
end
I don't know much about routes and stuff, so forgive me if this doesn't make sense, but doesn't it works for you?
map.resources :posts, :path_prefix => '/:username' do |post|
post.resources :comments
end
I can see here that this will generate the following
posts GET /:username/posts(.:format) {:controller=>"posts", :action=>"index"}
POST /:username/posts(.:format) {:controller=>"posts", :action=>"create"}
new_post GET /:username/posts/new(.:format) {:controller=>"posts", :action=>"new"}
edit_post GET /:username/posts/:id/edit(.:format) {:controller=>"posts", :action=>"edit"}
post GET /:username/posts/:id(.:format) {:controller=>"posts", :action=>"show"}
PUT /:username/posts/:id(.:format) {:controller=>"posts", :action=>"update"}
DELETE /:username/posts/:id(.:format) {:controller=>"posts", :action=>"destroy"}
post_comments GET /:username/posts/:post_id/comments(.:format) {:controller=>"comments", :action=>"index"}
POST /:username/posts/:post_id/comments(.:format) {:controller=>"comments", :action=>"create"}
new_post_comment GET /:username/posts/:post_id/comments/new(.:format) {:controller=>"comments", :action=>"new"}
edit_post_comment GET /:username/posts/:post_id/comments/:id/edit(.:format) {:controller=>"comments", :action=>"edit"}
post_comment GET /:username/posts/:post_id/comments/:id(.:format) {:controller=>"comments", :action=>"show"}
PUT /:username/posts/:post_id/comments/:id(.:format) {:controller=>"comments", :action=>"update"}
DELETE /:username/posts/:post_id/comments/:id(.:format) {:controller=>"comments", :action=>"destroy"}

Resources