Rails route for nested resource - ruby-on-rails

I keep receiving the below error message when trying to view the results of a search when using nested resource routes as below. For some reason I can't get rails to show the results of my search using the following routes and using the redirect_to #search call in the controller.
routes.rb:
resources :users do
resources :searches
end
Below is the Error:
NoMethodError in SearchesController#create
undefined method `search_url' for #<SearchesController:0x007fc68a881708>
Extracted source (around line #19):
17 #search = current_user.searches.create(search_params)
18
19 redirect_to #search
20
21 end
22
Searches Controller:
class SearchesController < ApplicationController
before_action :require_user
def index
end
def new
# #states = ["red","green","blue"]
#states = State.all
#cities = City.all
#languages = Language.all
#search = Search.new
end
def create
#search = current_user.searches.create(search_params)
redirect_to #search
#Old Search
##search = Search.create(search_params)
end
def show
##search = Search.find(params[:id])
##search = #user.searches.find(params[:id])
#search = current_user.searches.find_by(id: params[:id])
end
#Deleting searches, tied to the "delete link" on the view
def destroy
#search.destroy
flash[:success] = "Micropost deleted"
redirect_to request.referrer || #searches
end
private
def search_params
#:userid = #user.id
params.require(:search).permit(:searchname, :city, :min_gpa, :max_gpa, :firstname, :state, :city, :age, :gender, :universityname, :language, :livingin, :workexperience, :monthsspentabroadLiving, :monthsspentabroadworking, :degree , :degreetype, :countryofdegree, :wantstoworkin, :hasworkexperiencein, :permissiontoworkin, :currentlyemployed, :referencesuponrequest, :worktype, :charitywork)
end
end
New Search Form - View:
<%= bootstrap_form_for #search, url: user_searches_path(current_user), html: {class: "pure-form"} do |s| %>
<%= s.hidden_field :userid, :value => current_user.id %>
<div class="field">
<%= s.text_field :searchname, label: "Search Name" %>
</div>

If you do a bundle exec rake routes, you will see that you have this route:
user_search GET /users/:user_id/searches/:id(.:format) searches#show
This is because your searches resource is nested under the users resource. So, you need to pass the current_user and the #search to the user_search_path helper method.
So, the correct way to redirect to the user's search page is:
redirect_to user_search_path(current_user, #search)

Related

options_for_select on simple_form

I'm probably using this incorrectly and I cant figure it out.
I am using an options_for_select on my simple_form. It renders fine with no errors, but the selected option does not save to the database. All other fields save no problems.
The select_tag is
<%= select_tag :experiment_type, options_for_select(['AOV', 'Conversion']), :prompt => "Select a Project Type" %>
Controller:
class ExperimentsController < ApplicationController
before_action :find_advertiser
before_action :find_experiment, only: [:edit, :update, :show, :destroy]
def index
#experiments = Experiment.all.order("created_at DESC")
end
def show
end
def new
#experiment = Experiment.new
#advertisers = Advertiser.all.map{ |c| [c.name, c.id] }
end
def create
#experiment = Experiment.new(experiment_params)
#experiment.advertiser_id = params[:advertiser_id]
if #experiment.save
redirect_to advertiser_path(#advertiser)
else
render 'new'
end
end
def edit
#projects = Project.all.map{ |c| [c.name, c.id] }
end
def update
#experiment.advertiser_id = params[:id]
if #experiment.update(experiment_params)
redirect_to experiment_path(#experiment)
else
render 'edit'
end
end
def destroy
#experiment.destroy
redirect_to root_path
end
private
def experiment_params
params.require(:experiment).permit(:advertiser_id, :name, :experiment_type, :hypothesis, :priority, :status, :launch_date,
:description, :baseline_url, :test_url, :baseline_aov_60, :baseline_aov_30, :baseline_aov_mtd,
:baseline_conversion_60, :baseline_conversion_30, :baseline_conversion_mtd)
end
def find_advertiser
#advertiser = Advertiser.find(params[:advertiser_id])
end
def find_experiment
#experiment = Experiment.find(params[:id])
end
end
I would need your full form layout to tell you for sure, but according to your experiment_params method, experiment_type field is a part of experiment. However, when you use just select_tag it is not connected to your main object. You need to use just select. Similar to this:
<%= simple_form_for :experiment do |f| %>
...
<%= f.select ... %>
...
<% end %>
or in the simple_form format:
<%= f.input :experiment_type, collection: ['AOV', 'Conversion'] %>
My guess is also based on your hash:
"experiment_type"=>"AOV", "experiment"=>{"name"=>"Test" ....
The experiment_type is outside of your "experiment".

Radio Button with Multiple Values Rails

I want to have multiple values saved when a radio button is selected. I tried to do this with a hidden_field but it did not work.
<%= form_for #checkin do |f| %>
<% #api["results"][0..9].each do |n| %>
<%= f.label :name, n["name"] %>
<%= f.radio_button(:name, n["name"]) %></br>
<%= f.hidden_field :placeid, :value => n["place_id"] %>
<%end%>
<%= f.submit %>
<%end%>
I am looping through a Google maps api json response and would like to save the name and place_id when a radio button is selected and submitted. Right now only the name saves correctly.
Here is the controller where I am creating a new Checkin with the checkin_params
class CheckinsController < ApplicationController
def index
#checkins = Checkin.all
end
def create
#checkin = Checkin.new(checkin_params)
if #checkin.save
redirect_to #checkin
else
render 'new'
end
end
def show
#checkin = Checkin.find(params[:id])
end
private
def checkin_params
params.require(:checkin).permit(:name, :placeid)
end
end
And here is the Searches Controller where I get the #api from
class SearchesController < ApplicationController
def new
#search = Search.new
end
def create
#search = Search.new(search_params)
#search.ip_address = "50.172.64.130"
if #search.save
redirect_to #search
else
render 'new'
end
end
def show
#search = Search.find(params[:id])
response = Search.get("https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=#{#search.latitude},#{#search.longitude}&keyword=#{#search.keyword}&types=&rankby=distance&key=AIzaSyAny_eoq9b1UGL7Ow20vDTet9yIBb60BwA")
#api = response.parsed_response
#checkin = Checkin.new
end
private
def search_params
params.require(:search).permit(:keyword)
end
end
Any tips on my existing idea or a suggestion for another way to accomplish this would be greatly appreciated!

No route matches while creating nested resource in Rails

I am trying to create a new teacher for a specific school in my project and I got this error:
No route matches [POST] "/schools/3/teachers/new"
Here is my teachers_controller.rb:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def create
#teacher = Teacher.new(teacher_params)
#teacher.save
redirect_to school_path(school)
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
end
schools_controller.rb:
class SchoolsController < ApplicationController
def show
#school = School.find(params[:id])
end
def new
#school = School.new
end
def edit
#school = School.find(params[:id])
end
def update
#school = School.find(params[:id])
if #school.update(school_params)
redirect_to #school
else
render 'edit'
end
end
def index
#schools = School.all
end
def create
#school = School.new(school_params)
if #school.save
redirect_to schools_path
else
render 'new'
end
end
def destroy
#school = School.find(params[:id])
#school.destroy
redirect_to schools_path
end
private
def school_params
params.require(:school).permit(:name)
end
end
routes.rb:
Rails.application.routes.draw do
resources :schools do
resources :teachers
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 'welcome#index'
And teachers/new.html.erb:
<%= form_for :teacher, url: school_teachers_path(school) do |f| %>
<p>
<%= f.label :firstName %><br>
<%= f.text_field :firstName %>
</p>
<p>
<%= f.label :lastName %><br>
<%= f.text_field :lastName %>
</p>
<p>
<%= f.label :middleName %><br>
<%= f.text_field :middleName %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
As your teacher resource is nested under the school resource, so you need to pass the school when you try to create a teacher.
Try changing your new and create actions in teachers_controller.rb to something like this:
def new
#school = School.find(params[:school_id])
#teacher = #school.teachers.build
end
def create
#school = School.find(params[:school_id])
#teacher = #school.teachers.build(params[:teacher])
#teacher.save
redirect_to school_path(#school)
end
And, then change your form to this:
<%= form_for([#school, #teacher]) do %>
. . .
. . .
<% end %>
Try this in your form:
<%= form_for [school, Teacher.new] do |f| %>
The path you are posting to is for the index of teachers at a school:
school_teachers GET /schools/:school_id/teachers(.:format) teachers#index
I believe that it's a has_many belongs_to association. So you need to first change your teacher controller create action and new action.
class TeachersController < ApplicationController
def new
get_school
#teacher = #school.teachers.build
end
def create
get_school
#teacher = #school.teachers.build(teacher_params)
If #teacher.save
redirect_to school_path(school)
else
render 'new'
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
def get_school
#school = School.find (params [:school_id])
end
end
Then in your form you 'll do :
<%= form_for([#school,#teacher]) do |f| %>
Hope this will help

Undefined method error when using Searchkick with pagination

I am trying to implement a search function on my Rails app to get a search box working.
However, when running the code, the following error is raised:
NoMethodError in PostsController#index undefined method `paginate' for #<Searchkick::Results:0x007f3ff123f0e0>
(I also have a tag cloud, which is working fine if I keep the code below unchanged, but if I change #posts = #posts to #posts = Post.search it breaks the tag functionality too.)
I am using:
Rails 4.2.0
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]
Code:
Here is how my PostsController looks like:
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
#post = Post.friendly.find(params[:id])
end
def update
#post = Post.friendly.find(params[:id])
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to root_path
end
def index
if params[:tag]
#posts = Post.tagged_with(params[:tag]).paginate(page: params[:page], per_page: 5)
else
#posts = Post.order('created_at DESC').paginate(page: params[:page], per_page: 2)
end
if params[:nil].present?
#posts = #posts.search(params[:nil]).paginate(page: params[:page])
else
#posts = #posts.paginate(page: params[:page])
end
end
def show
#post = Post.friendly.find(params[:id])
end
def autocomplete
render json: Post.search(params[:query], autocomplete: true, limit: 5).map(&:title)
end
private
def find_post
#post = Post.friendly.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :description, :content, :tag_list, :preview)
end
end
end
This is how my navbar search form looks like
<li class="navs">
<%= form_tag posts_path, method: :get do%>
<%= text_field_tag :search, params[:query], placeholder: "Search Blog", name: "nil" , required: "", class: "input-field", id: "post_search", autocomplete: "off" do %>
<%= submit_tag "", class: "material-icons search-box" %>
<% end %>
<% if params[:search].present? %>
<%= link_to "X", posts_path %>
<% end %>
<% end %>
</li>
I have searched a lot and couldn't find any answers specific that could give me a right direction as to what I am doing wrong.
I would really appreciate any help.
The problem is that the search call will return a Searchkick::Results collection, rather than an ActiveRecord::Relation. The latter has been patched with the paginate method, while the former has not, thus raising a NoMethodError.
According to the documentation, you should be able to make this work by passing the pagination parameters to the search method:
#posts = #posts.search(params[:nil], page: params[:page])
Alternatively to doing pagination within the SeachKick query you can just do the following in a separate step.
#posts = Kaminari.paginate_array(#posts).page(params[:page])

Rails - Updating and deleting content?

EDIT: I managed to delete! i had to define teh instance variable #movies = Movie.find(params[:id]) to the delete method in the controller.
I still can't update though. I get "param is missing or the value is empty: movie"
I forgot to add my contrller! sorry!
I'm trying to replicate one of my in class exercises into another app, for practice.
The idea is to be able to add new movies into a database, and get the option to update their info, and delete them as well. I can add new content, but I can't update them or delete them.
Appreciate any inputs I can get.
Routes.rb
Rails.application.routes.draw do
root "movies#index"
get "/movies", to: "movies#index"
get "/movies/new", to: "movies#new", as: "new_movie"
get '/movies/:id', to: "movies#movie_page", as: "movie_page"
post "/movies", to: "movies#add"
get "/movies/:id/edit", to: "movies#edit", as: "movie_edit"
put "/movies/:id", to: "movies#update"
patch "/movies/:id", to: "movies#update", as: "update_movie"
delete "/movies/:id", to: "movies#delete", as: "delete_movie"
end
Controller
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
def movie_page
#movies = Movie.find(params[:id])
end
def new
#movies = Movie.new
end
def add
#movies = Movie.create(movie_params)
redirect_to movies_path
end
def edit
#movies = Movie.find(params[:id])
end
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def delete
#movies = Movie.find(params[:id])
#movies.destroy
# flash[:notice] = "Shirt was deleted."
redirect_to root_path, notice: "Shirt was deleted."
end
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
# def set_movie
# #movies = Movie.find(params[:id])
# end
end
Form partial
<%= form_for #movies do |m| %>
<p>
<%= m.label :title %><br>
<%= m.text_field :title %>
</p>
<p>
<%= m.label :description %><br>
<%= m.text_field :description %>
</p>
<p>
<%= m.label :year_released %><br>
<%= m.text_field :year_released %>
</p>
<p>
<%= m.submit %>
</p>
<% end %>
Movie page html (individual movies, labeled by IDs)**I can't update or Delete, no route matches Delete.
When I press Update - I get param is missing or the value is empty: movie
<h1><%= #movies.title %></h1>
<h2>Released on : <%= #movies.year_released %> </h2>
<p> <%= #movies.description %> </p>
<%= link_to "Update", movie_edit_path(#movies) %>
<%= link_to "Delete", movies_path, method: :delete %
Edit page *I cant access this link. the form is the problem
<h1>Edit <%= #movies.title %> Info </h1>
<%= render "form" %>
<%= link_to "Cancel Edit", movie_edit_path(#movies) %>
Many thanks guys
def update
#movie = Move.find(params[:id])
#movie.update(movie_params)
redirect_to movie_path(#movie)
end
on your routes. all you need is resources :movies
you are getting param is empty because you have to pass in the id of the movie to update.
The major issue is that you do not load the variable #movies from the DB before you use it.
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def update
#movies.find(params[:id])
#movie.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
Aside from that you have tons of duplication and quite a few idiosyncrasies.
Rails uses these naming conventions for actions:
index
show (not movie_page)
new
create (not add)
edit
update
destroy (not delete)
You should follow them unless you have a damn good reason not to.
class MoviesController < ApplicationController
# cuts the duplication
before_filter :set_movie, except: [:new, :index]
def index
#movies = Movie.all
end
# GET /movies/:id
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# POST /movies
def create
#movie = Movie.create(movie_params)
redirect_to movies_path
end
# GET /movies/edit
def edit
end
# PUT|PATCH /movies/:id
def update
#movie.update(movie_params)
redirect_to #movie, notice: "Shirt was updated."
end
# DELETE /movies/:id
def destroy
#movie.destroy
redirect_to action: :index
end
private
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
def set_movie
# Use the singular form when naming a variable with a single record
# failure to do so may result in tarring and feathering
#movie = Movie.find(params[:id])
end
end

Resources