trying to get rails routing to "click" and just not getting it
have a project and a task model:
class Task
include Mongoid::Document
field :title, :type => String
has_many :projects
belongs_to :user
end
class Project
include Mongoid::Document
field :title, :type => String
has_and_belongs_to_many :tasks
belongs_to :user
end
I want to "associate" a task with a project
so I have this in the project controller:
def connect
#project = Project.find(params[:id])
#project.tasks_ids.push(params[:task_id])
#project.save
redirect_to project
end
with this route:
resources :projects do
match 'connect/:id' => 'projects#connect', :as => :connect, :via => :put
resources :tasks
end
I cant seem to get this to work in the view:
= link_to 'Associate Task', project_connect_path(#task)
fails with:
No route matches {:controller=>"projects", :action=>"connect"}
resources :projects do
member do
put :connect
end
resources :tasks
end
Your path should look like this:
= link_to 'Associate Task', project_connect_path(#project, :task_id => #task.id), :method => :put
Try to do this:
resources :projects do
member do
put 'connect'
end
resources :tasks
end
or you can write your route above the resources :projects do ...
and here is the link, you can read more about routes there: Rails routes
Related
I'm trying to allow a User to favorite a coffee_roast. However on trying to load the show page I get a NoMethod Error
undefined method `favorite_coffee_roast_path'
which comes from this line of code:
<%= link_to "Add to favorites", favorite_coffee_roast_path(#coffee_roast, type: "favorite"), method: :put %><br />
I have tried a number of variations such as:
favorite_roast_coffee_roast_path
favorite_coffeeroast_coffee_roast_path
favorite_coffee_roast_coffee_roast_path
None obviously work.
My Models
class User < ApplicationRecord
has_merit
has_one :drink
has_many :coffeeshops
has_many :coffee_roasts
has_many :favorite_coffeeroasts
has_many :favorite_roasts, through: :favorite_coffeeroasts, source: :coffee_roast
class CoffeeRoast < ApplicationRecord
has_many :favorite_coffeeroasts
has_many :favorited_by, through: :favorite_coffeeroasts, source: :user
class FavouriteCoffeeroast < ApplicationRecord
belongs_to :coffee_roast
belongs_to :user
My Controller
class CoffeeRoastsController < ApplicationController
...
def favorite_coffeeroast
#coffee_roast = CoffeeRoast.find(params[:id])
type = params[:type]
if type == "favorite"
current_user.favorite_roasts << #coffee_roast
redirect_to #coffee_roast, notice: "You favorited #{#coffee_roast.name}"
elsif type == "unfavorite"
current_user.favorite_roasts.delete(#coffee_roast)
redirect_to #coffee_roast, notice: "Unfavorited #{#coffee_roast.name}"
else
# Type missing, nothing happens
redirect_to #coffee_roast, notice: "Nothing happened."
end
end
routes.rb
Rails.application.routes.draw do
#core root
get 'home/index' => 'home#index'
root 'home#index'
#roasts redirect
get '/roasts', to: redirect('/coffee_roasts', status: 302)
namespace :api do
namespace :v1 do
resources :roasts
end
end
resources :blends
resources :roasters
resources :countries
resources :regions
resources :comments
resources :coffee_flavours
resources :flavours
resources :drinks
devise_for :users
devise_for :admins
resources :varietals
resources :tags
resources :coffee_beans
resources :coffee_roasts
resources :processings
get 'contact-me', to: 'messages#new', as: 'new_message'
post 'contact-me', to: 'messages#create', as: 'create_message'
#static pages
get 'about', to: 'pages#about'
get 'cookiepolicy', to: 'pages#cookiepolicy'
get 'map', to: 'pages#map'
get 'longblack', to: 'longblack#index'
get 'prices', to: 'prices#new'
post 'prices', to: 'prices#create'
#db resources
resources :roasters do
resources :comments
end
resources :articles do
resources :comments
end
resources :coffeeshops do
resources :comments
end
resources :roasts do
resources :comments
end
resources :coffee_roasts do
resources :comments
end
resources :coffeeshops do
put :favorite, on: :member
end
resources :coffeeshops do
put :bookmarked, on: :member
end
Why can't I find the right path? What am I missing?
Looks like you need to read more about routing in ROR. Add the new action to existing resources :coffee_roasts:
resources :coffee_roasts do
put :favorite_coffeeroast, on: :member
resources :comments
end
Also you are duplicating routes when you write them with and without nesting. Since you want to nest everywhere comments routes you can remove corresponding routes without nesting
I need to define a method/action in my LessonsController that I can call from the lesson show action that marks the lesson as being completed by the current user. What does that controller method look like?
Here's the overview of my models:
User
has_many :completions
has_many :completed_steps, through: :completions, source: :lesson
Lesson
has_many :completions
has_many :completed_by, through: :completions, source: :user
Completions
belongs_to :user
belongs_to :lesson
My Completions Table looks like this:
t.integer "user_id"
t.integer "lesson_id"
t.boolean "completed_step"
t.string "completed_by"
I'm assuming in the LessonsController it looks like this
def complete_step
self.completions.create(completed_step: true, user_id: current_user.id)
end
Routes info:
Rails.application.routes.draw do
namespace :admin do
resources :users
resources :coupons
resources :lessons
resources :plans
resources :roles
resources :subscriptions
resources :completions
root to: "users#index"
end
devise_for :users, :controllers => { :registrations => "registrations"}
# Added by Koudoku.
mount Koudoku::Engine, at: 'koudoku'
scope module: 'koudoku' do
get 'pricing' => 'subscriptions#index', as: 'pricing'
end
resources :lessons do
member :complete
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'pages#home'
get '/dashboard' => 'pages#dashboard', :as => 'dashboard'
mount StripeEvent::Engine, at: '/stripe-events' # prov
end
Here's my button link to make this functional.
<%= button_to "Mark this Lesson as Complete", complete_lesson_path(#lesson), method: :put, class: "btn btn-warning btn-lg" %>
Will this work or am I WAY off? Thanks!
Keep this is the LessonsController, but change it in either of the following ways:
def complete_step
current_user.completions.create(completed_step: true, lesson_id: #lesson.id)
end
# ~~ OR ~~
def complete_step
#lesson.completions.create(completed_step: true, user_id: current_user.id)
end
Both of these assume that you've already set #lesson in the controller, probably in a before_action :set_lesson.
EDIT:
If you need a route suggestion, then assuming you have resources :lessons in your routes file, you can either use an existing route (likely update) or add a member route like this:
resources :lessons do
get 'complete', on: :member
end
If you add a route, then you will need to add an action that looks like
def complete
complete_step
redirect #lesson
end
or similar, however you want to handle the response itself. You will also need to ensure that #lesson is set, so you should tweak your before_action :set_lesson, only: [:show, :update, ...] to also include :complete
Please try with below code.in your completion controller
def create
#lession = Lession.find(params[:lession_id])
#completion = current_user.completions.create(completed_step: true, lesson_id: #lesson.id)
redirected_to #completion
end
You can also just pass user: current_user to the completions.create method instead of passing in the current_user.id
Something like #lesson.completions.create(completed_step: true, user: current_user)
I am currently using Pg gem search in my application. Now, I want to use the pg search to search for the data across two models which are school and teacher. I created a welcome page let the audience use the search functionality there. However, at the moment I am wondering how can I retrieve the result after the audience enter the query, for example, if they type a specific name of a teacher or a school, I want to return that teacher/school with a link so that the user can click on and find out more information about that school/teacher.
Here are my files:
search.haml:
.row
%h1.text-center Tìm Trường Học và Giáo Viên
= form_tag search_welcome_index_url, :id => 'custom-search-input', method: :get, class: "input-group col-md-12", role: "search" do
.input-group
= text_field_tag :search,
params[:search], class: "search-query form-control", placeholder: "Tên trường học, ví dụ: Đại Học Bách Khoa Hồ Chí Minh...."
%span.input-group-btn
= button_tag( :class => "btn btn-danger") do
.search-size
%span.glyphicon.glyphicon-search
= #results
welcome_controller.rb:
class WelcomeController < ApplicationController
def welcome
end
def search
#results = PgSearch.multisearch(params[:search])
end
end
teacher.rb:
class Teacher < ActiveRecord::Base
include PgSearch
multisearchable against: [:full_name]
belongs_to :school
has_many :ratings
end
school.rb:
class School < ActiveRecord::Base
include PgSearch
multisearchable :against => [:name]
has_many :teachers, dependent: :destroy
end
routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :welcome do
collection do
get 'search'
end
end
resources :schools do
collection do
get 'search'
end
resources :teachers do
collection do
get 'search'
end
end
end
resources :teachers do
resources :ratings
end
root 'welcome#welcome'
end
I have the following route definition:
resources :documents do
collection do
post :filter
end
end
and the following model structure:
class Document < ActiveRecord::Base
belongs_to :documentable, :polymorphic => true
end
class User < ActiveRecord::Base
has_many :documents, :as => :documentable
end
and controller structure:
class DocumentsController < ApplicationController
def index
# not important
end
def filter
# not important
end
end
I can easily in a view say:
polymorphic_path([#user, Document])
to get the path /users/1/documents, but I want to be able to say:
filter_polymorphic_path([#user, Document])
to get the path /users/1/documents/filter, unfortunately, this doesn't work.
Anyone know how I can pull this off without adding the following to my routes, for each of my documentable models:
resources :users do
resources :documents do
collection do
post :filter
end
end
end
polymorphic_path([#user, Document], :action => 'filter') gives you /users/:user_id/documents/filter.
Also, polymorphic_path([#user, Document], :action => 'filter', :sort_order => 'this-order') gives you /users/:user_id/documents/filter?sort_order=this-order.
I ran into the same problem thinking you can replace the edit in edit_polymorphic_path to whatever method you want.
See: http://api.rubyonrails.org/classes/ActionDispatch/Routing/PolymorphicRoutes.html
This would do it, and it reads nicely.
polymorphic_path([:filter, #user, Document])
Or these
polymorphic_path([:filter, #user, :documents])
polymorphic_path([:filter, #user, Document.new])
And with a query param
polymorphic_path([:filter, #user, Document], :q => 'keyword')
And, in a view you can also do this:
= link_to "Documents", [[:filter, #user, :documents], :q => 'keyword']
Currently
Project101::Application.routes.draw do
match '/:id' => 'companies#show'
resources :companies do
resources :customers
resources :users
resources :categories
resources :addresses
end
devise_for :users
resources :users, :controller => "users"
root :to => "companies#index"
end
Everything belongs to a company. Trying to create routes like www.example.com/:id/customers where :id is always the company id.
At the moment www.example.com/:id works but all url's are generated as /companies/:id/cusotmers.
Saw Rails 3 Routing Resources with Variable Namespace.
Is this the right way of doing this?
EDIT
Kept :as => :company to help generate the URL's, Links, etc a little easier for me. Sure others could do cleaner or better method. Also had to manually create the edit, destroy, new with different urls so I could use them in links if user was admin.
Project101::Application.routes.draw do
match '/' => 'companies#index'
match '/companies' => 'companies#index'
match '/:company_id' => 'companies#show', :as => :show_company
match '/companies/:id/edit' => 'companies#edit', :as => :edit_company
match '/companies/:id/new' => 'companies#new', :as => :new_company
match '/companies/:id/destroy' => 'companies#destroy', :as => :delete_company
scope '/:company_id', :as => :company do
resources :customers
resources :users
resources :categories
resources :services
resources :addresses
end
devise_for :users
resources :users, :controller => "users"
root :to => "companies#index"
end
Then just used basic nested_resources for links, controllers and forms.
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_company
def current_company
if params[:company_id] != nil
#current_company ||= Company.find(params[:company_id])
else
#current_company = nil
end
return #current_company
end
end
Basic links
<%= link_to "Customers", company_customers_path(current_company) %>
links for specific customer
<%= link_to #customer.name, edit_company_customer_path(current_company, #customer) %>
Controllers look like
class CustomersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def new
#company = current_company
#customer = #company.customers.new
end
def create
#customer = Customer.new(params[:customer])
if #customer.save
flash[:notice] = "Successfully created customer."
redirect_to company_customer_path(current_company, #customer)
else
render :action => 'new'
end
end
end
And finally my forms look like
<%= form_for [#company, #customer] do |f| %>
<%= f.error_messages %>
....
<% end %>
Yes, if you always want the routes to begin with the company id you can wrap them in a scope like this:
scope ":company_id" do
resources :customers
resources :users
resources :categories
resources :addresses
end