Rails4: Link to A Controller - ruby-on-rails

I have a User's Show Page where
1.) Routes
get 'users/:id' => 'user#show', as: :user
2.) user_controller.rb
class UserController < ApplicationController
before_filter :authenticate_user!, only: :show
def show
#user = User.find_by_name(params[:id]) # for name instead of id
#listings = #user.listings
end
end
and i can link to it via "current_user".
I wanted to create a Shop Controller, so i followed the same steps. I Generated a Shops Controller and modified the routes and controller as follow:
1.) Routes
get 'users/:id' => 'user#show', as: :user
get 'shop/:id' => 'shop#show', as: :shop
2.) shop_controller.rb
class ShopController < ApplicationController
before_filter :authenticate_user!, only: :show
def show
#user = User.find_by_name(params[:id]) # for name instead of id
#listings = #user.listings
end
end
This Works only if im at the User's Page (localhost:3000/users/test) and then click the link to the controller. then it switches to (localhost:3000/shop/test).
If i try to click the link anywhere else im getting
The link is ->
<li><%= link_to "My Shop", :controller => "shop", :action => "show" %></li>
I'm fairly new to Rails, if someone could enlighten me it would be very nice :)

First start with correcting names of your controllers as per rails conventions. Names should be as follows.
controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!, only: :show
def show
#user = User.find(params[:id]) # Because Id can't be same for two users but name can be.
#listings = #user.listings
end
end
And in case of shop_controller it is fine beacuse shop is not a model.
controllers/shop_controller.rb
class ShopController < ApplicationController
before_filter :authenticate_user!, only: :show
def show
#user = User.find(params[:id]) # Id can't be same for two users but name can be.
#listings = #user.listings
end
end
And give link like this.
<%= link_to "My Wonderful Shop", {:controller => "shop", :action => "show", :id => #user.id} %>
In your routes file
get 'shop/:id' => 'shop#show'

Related

Fix inconsistent route names (Rails)

Routes
resources :favorites, only: [ :index, :create, :destroy ] , param: :listing_id
Rake routes
favorites GET /favorites(.:format) favorites#index
favorites POST /favorites(.:format) favorites#create
favorite DELETE /favorites/:listing_id(.:format) favorites#destroy
Notice the (s) in favorites, why is it not all favorite or favorites?
I create one favorite and destroy one favorite, so I think it should be singular in both.
I need
favorite POST /favorites/:listing_id(.:format) favorites#create
I tried this in my routes:
resources :favorites, only: [ :index, :destroy
] , param: :listing_id
post 'favorites/:listing_id' => 'favorite#create', as: :favorite
but get this error:
ArgumentError: Invalid route name, already in use: 'favorite' You may
have defined two routes with the same name using the :as option, or
you may be overriding a route already defined by a resource with the
same naming. For the latter, you can restrict the routes created with
resources as explained here:
http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
How do I modify this one?
How do I keep it consistent as I need create path and destroy path consistent in my view for a number of reasons.
My controller
class FavoritesController < ApplicationController
before_action :load_listing, only: [:create, :destroy]
def index
#favorites = current_user.favorites.map{|i| i.id} || []
#listings = ListingsQuery::Search.call(:favorited_ids=> current_user.favorites.map{|i| i.id} )
respond_to do |format|
format.html {}
format.js {}
end
end
def create
if current_user.favorite!(#listing)
format.js {}
end
end
def destroy
if current_user.unfavorite!(#listing)
format.js {}
end
end
private
def load_listing
#listing_id = favorite_params[:listing_id]
#listing = Listing.find(#listing_id)
end
def favorite_params
params.permit(:listing_id)
end
end
view
<% if listing.is_favorited == true %>
<%= link_to favorite_path(:listing_id => listing.listing_id), method: :delete, remote: true do%>
<i id='i-<%= listing.listing_id %>' class=" fa fa-heart"></i>
<% end %>
<% else %>
<%= link_to favorite_path(:listing_id => listing.listing_id), method: :post, remote: true do %>
<i id='i-<%= listing.listing_id %>' class="fa fa-heart-o"></i>
<% end %>
<% end %>
create.js
(function(){
$("#i-<%= #listing_id %>").removeClass('fa-heart-o');
$("#i-<%= #listing_id %>").addClass('fa-heart');
$("#i-<%= #listing_id %>").parent().attr("data-method",'delete');
})();
Why is this...
resources :favorite do
collection do
post "for_lisiting/:listing_id", action: :create_for_listing
delete "for_listing/:listing_id", action: :delete_for_listing
end
end
preferred over this..
match 'favorite' => 'favorites#create', via: :post
match 'favorite' => 'favorites#destroy', via: :delete
It seems to me, but maybe I am wrong. that
/favorite/for_lisiting/:listing_id(.:format)
is unnecessarily long compared to
/favorite/:listing_id(.:format)
however, I am a novice, so value your reasoning.
When using rails resource helper, it creates some REST endpoints. You have listings that can be favorited, you are mixing both resources. Your resource is the Listing and favorite/unfavorite/favorites are actions on the resource.
Try something like this:
resources :listings do
member do
post :favorite, action: :create_favorite
delete :favorite, action: :delete_favorite
get :favorites
end
end
That will give you two route: /listings/:id/favorite (both for create -POST- and delete -DELETE-) and /listings/:id/favorites (GET). Both create and delete will be the same favorite_listing_path(listing) (or similar, check rake routes).
Now, on your ListingsController, define those actions:
class ListingsController < ApplicationController
def create_favorite
Listing.find(:id).favorites.create(user: current_user)
redirect_to :something, notice: 'Favorited'
end
def delete_favorite
Listing.find(id).favorites.where(user: current_user).destroy_all
redirect_to :something, notice: 'Unfavorited'
end
def favorites
#favorites = Listing.find(id).favorites
end
# of course, you could add a before_action to DRY it, I just wanted to be explicit on which is the actual resource
end

Displaying item with a specific parameter in the index

I am building a website for poetries.
There are two different type of poetries: famous or amateur.
I built the CRUD functions to display all the poetries (famous and amateur, without distinction) and this is working as intended (see the PoetrisController code below).
Now, I want to give the possibility to the user to choose if he wants to see only the amateur poetries or famous ones.
Basically the user clicks the link "Amateur" or "Famous" in the navbar and he is redirected to a new page listing only amateur or famous poetries.
My question is: should I create another Controller (for example PoetriesFamousController) and creating a index function inside it to display only the famous poetries or there is a way to use the already existing PoetriesController to show only the "famous poetries" if the user clicks the link in the navbar?
PoetriesController:
class PoetriesController < ApplicationController
skip_after_action :verify_authorized, only: [:home, :about, :newsletter, :disclaimer, :new, :create]
skip_before_action :authenticate_user!, only: [:home, :about, :newsletter, :disclaimer, :new, :create]
before_action :set_poetry, only: [:show, :edit, :update, :destroy,]
before_action :authenticate_user!, except: [:index, :amateur_poetries]
def index
if params[:search]
#poetries = policy_scope(Poetry).search(params[:search]).order("created_at DESC").limit(30)
else
#poetries = policy_scope(Poetry).order("RANDOM()").limit(30)
end
end
def show
authorize #poetry
end
def new
#poetry = Poetry.new
end
def create
Poetry.create(poetry_params)
redirect_to poetries_path
end
def edit
authorize #poetry
end
def update
#poetry.save
redirect_to poetry_path(#poetry)
end
def destroy
#poetry.destroy
redirect_to poetries_path
end
private
def poetry_params
params.require(:poetry).permit(:title, :author, :body, :poster, :country)
end
def set_poetry
#poetry = Poetry.find(params[:id])
end
end
Poetries.rb
class Poetry < ApplicationRecord
def self.search(search)
where("lower(title) LIKE ? OR lower(author) LIKE ? OR lower(country) LIKE ? OR lower(born) LIKE ?", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%")
end
end
Routes.rb
get 'poetries', to: 'poetries#index', as: :poetries
get "poetries/new", to: "poetries#new"
post "poetries", to: "poetries#create"
get "poetries/:id/edit", to: "poetries#edit"
patch "poetries/:id", to: "poetries#update"
get 'poetries/:id', to: 'poetries#show', as: :poetry
delete "poetries/:id", to: "poetries#destroy"
Here is some idea for your problem
In your view (sample idea)
poetries type:
<%= select_tag :poetries_type, options_for_select(["Famous","Amateur"]), include_blank: true, :class => 'form-control' %>
in your controller:
def index
if params[:search]
if params[:poetries_type] == "Famous"
#poetries = Poetry.famous.search(params[:search]).order("created_at DESC").limit(30)
elsif params[:poetries_type] == "Amateur"
#poetries = Poetry.amateur.search(params[:search]).order("created_at DESC").limit(30)
else
#poetries = Poetry.search(params[:search]).order("created_at DESC").limit(30)
end
else
#poetries = policy_scope(Poetry).order("RANDOM()").limit(30)
end
end
Poetries.rb, add two scope for famous an amateur
def self.amateur
where("poster != ?","Admin")
end
def self.famous
where("poster = ?","Admin")
end
The simplest thing would be to add two more actions to your controller.
def famous
#poetries = #get the famous ones
render :index
end
def amateur
#poetries = #get the amateur ones
render :index
end
Then update your routes
get 'poetries', to: 'poetries#index', as: :poetries
get 'poetries/famous', to: 'poetries#famous'
get 'poetries/amateur', to: 'poetries#amateur
# rest of the routes

Why am I getting a recordnotfound error when trying to access an instance in rails?

I have a user profile controller called "userinfo" and it's corresponding view. The userinfo index is the root path. In the homepage(which is the userinfo index), I have a link that takes you to the user profile page. It is giving me this error when I go to the home page:
My routes are:
My userinfos_controller:
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#userinfors = Userinfo.find(params[:id])
end
def show
#myvideo = Video.last
end
def new
#userinformation = current_user.userinfos.build
end
def create
#userinformation = current_user.userinfos.build(userinfo_params)
if #userinformation.save
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
end
def destroy
#userinformation.destroy
redirect_to userinfo_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.find(params[:id])
end
end
and my view is:
<%= link_to 'profile', userinfors_path(#userinfors) %>
My routes.rb file:
Rails.application.routes.draw do
devise_for :users
resources :userinfos do
resources :videos
end
resources :pages
get '/application/decide' => 'application#decide'
root 'userinfos#index'
get '/userinfos/:id', to: 'userinfos#show', as: 'userinfors'
end
Thanks for any help!
ok, there are multiple errors and you are not following conventions of rails, index is not for what you have used.
Index is used to list all the users and show for a particular one with id passed in params.
Your index path is, as you can see, /userinfos which is correct and it doesn't have any id with it but you are trying to find user with params[:id] which is nil and hence the error.
Lets try out this:
def index
#userinfors = Userinfo.all #pagination is recommended
end
In your index view,
<% #userinfors.each do |userinfor| %>
<%= link_to "#{userinfor.name}'s profile", userinfo_path(userinfor) %>
<% end %>
It should work now.
Please read routing and action controller to get the idea and understand the magic behind rails routing and mvc architecture..

How to determine which route was matched for a controller#action?

Consider the example in the note for this guide on routing and singular resources Both of these would be directed to 'photos#index', but are different contexts.
/users/1/photos (might list a user's photos)
/photos (list all users' photos)
I want to give the user different options depending on which route was followed to access.
There are two ways to assign this issue.
1st way
In the users_controller.rb
before_action :set_user, only: [:photos]
def photos
#photos = #user.photos
render "photos/index"
end
private
#user = User.find(params[:id])
In routes.rb you need to add this route,
resources :users do
get "photos", on: :member
end
2nd way
In photos_controller.rb
before_action :set_user, only: [:photos]
def index
unless #user.nil?
#photos = #user.photots
else
#photos = Photo.all
end
end
private
def set_user
if params[:user_id].present?
#user = User.where(params[:user_id]).first
end
end
Well first of all, I'd make /users/1/photos an action off users controller instead. However, if you really want to do what you say there, you could check for presence of the user_id param on the photos controller index and fashion your finder appropriately.
For example you can validate route match with rspec, something like the following:
expect(:get => "/users/1/photos").to route_to(
:controller => "photos",
:user_id => "1",
)

uninitialized constant YourSpace::UsersController::User

error
uninitialized constant YourSpace::UsersController::User
controller
class YourSpace::UsersController < ApplicationController
def new
#title = YourSpace
end
def edit
#title = YourSpace
#user = User.find(params[:id])
end
def update
name = params[:user][:name]
if name.blank?
flash[:notice] = "Name can not be blank dawg!"
redirect_to :back
else
User.find(params[:id]).update_attributes(params[:user])
# redirect_to :action 'show'
redirect_to :action => :show
# render :action => 'show'
end
end
def index
#title = YourSpace
#users = User.limit(100).order('created_at DESC')
end
def show
#title = YourSpace
#user = User.find(params[:id])
end
end
routes
Rails.application.routes.draw do
root 'site#home'
get '/about', to: 'site#about', as: :about
namespace :your_space do
resources :users
end
namespace :word_cloud do
resources :words, :only => [:index, :create]
end
namespace :word_clock do
resources :page, :only => [:index]
end
namespace :wish do
resources :page, :only => [:index]
end
end
when firing up the rails server, I get error in the YourSpace UsersController where this line of code #users = User.limit(100).order('created_at DESC') is apparently all jacked up. Please know I'm trying to duplicate 180 websites in 365 days which is mostly built using ruby and rails. I'm following closely along the repo to build muscle memory. very much new to learning how to think, and programming.
First thought was wrong.. to solve the problem change User to ::User
My first thought is that you need to put this YourSpace::UsersController in app/controllers/your_space/users_controller.rb. Rails forces directory structure.

Resources