I have two models with has_many and belongs_to with nested resources and independent views. I have created nav-tabs which I wish to be rendered by both controllers. The nav-tabs works for trip view but does not work in location index. I need to pass local.. something to get working and I don't know how. This is the error I get.
No route matches {:action=>"show", :controller=>"trips", :trip_id=>"13"} missing required keys: [:id] for this line:
a.slow href=send("trip_url") Trip
Trip Model
class Trip < ApplicationRecord
has_many :user_trips
has_many :users, through: :user_trips, dependent: :destroy
belongs_to :creator, class_name: "User"
# has_many :locations, dependent: :destroy
# belongs_to :location, optional: true, inverse_of: :locations
has_many :locations
accepts_nested_attributes_for :locations, :reject_if => :all_blank, :allow_destroy => true
end
location model
class Location < ApplicationRecord
# has_many :trips, inverse_of: :trips
belongs_to :trip, optional: true
# accepts_nested_attributes_for :trips, :reject_if => :all_blank, :allow_destroy => true
end
Routes
Rails.application.routes.draw do
resources :locations
resources :trips do
resources :locations
end
end
trip controller
class TripsController < ApplicationController
before_action :set_trip, only: [:show, :edit, :update, :destroy]
# GET /trips
# GET /trips.json
def index
#trips = Trip.all
end
# GET /trips/1
# GET /trips/1.json
def show
end
# GET /trips/new
def new
#user = current_user
#trip = current_user.trips.build
end
# GET /trips/1/edit
def edit
#user = current_user
end
# POST /trips
# POST /trips.json
def create
#user = current_user
#trip = current_user.trips.build(trip_params)
respond_to do |format|
if #trip.save
# #trip.users << #user
format.html { redirect_to #trip, notice: 'Trip was successfully created.' }
format.json { render :show, status: :created, location: #trip }
else
format.html { render :new }
format.json { render json: #trip.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /trips/1
# PATCH/PUT /trips/1.json
def update
respond_to do |format|
if #trip.update(trip_params)
format.html { redirect_to #trip, notice: 'Trip was successfully updated.' }
format.json { render :show, status: :ok, location: #trip }
else
format.html { render :edit }
format.json { render json: #trip.errors, status: :unprocessable_entity }
end
end
end
# DELETE /trips/1
# DELETE /trips/1.json
def destroy
#trip.destroy
respond_to do |format|
format.html { redirect_to trips_url, notice: 'Trip was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_trip
#trip = Trip.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def trip_params
params.require(:trip).permit(:name, :description, :creator_id, :location_id, user_ids: [])
end
end
location controller
class LocationsController < ApplicationController
# before_action :set_location, only: [:show, :edit, :update, :destroy]
# before_action :set_trip
# GET /locations
# GET /locations.json
def index
trip = Trip.find(params[:trip_id])
#locations = trip.locations
# #locations = trip.locations
end
# GET /locations/1
# GET /locations/1.json
def show
#trip = Trip.find(params[:trip_id])
trip = Trip.find(params[:trip_id])
#location = trip.locations.find(params[:id])
end
# GET /locations/new
def new
trip = Trip.find(params[:trip_id])
#location = trip.locations.build
end
# GET /locations/1/edit
def edit
trip = Trip.find(params[:trip_id])
#2nd you retrieve the comment thanks to params[:id]
#location = trip.locations.find(params[:id])
end
# POST /locations
# POST /locations.json
def create
# #location = Location.new(location_params)
trip = Trip.find(params[:trip_id])
#location = trip.locations.create(params[:location_params])
respond_to do |format|
if #location.save
format.html { redirect_to trip_locations_url, notice: 'Location was successfully created.' }
format.json { render :show, status: :created, location: #location }
else
format.html { render :new }
format.json { render json: #location.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /locations/1
# PATCH/PUT /locations/1.json
def update
trip = Trip.find(params[:trip_id])
#location = trip.locations.find(params[:id])
respond_to do |format|
if #location.update(location_params)
format.html { redirect_to trip_locations_url, notice: 'Location was successfully updated.' }
format.json { render :show, status: :ok, location: #location }
else
format.html { render :edit }
format.json { render json: #location.errors, status: :unprocessable_entity }
end
end
end
# DELETE /locations/1
# DELETE /locations/1.json
def destroy
trip = Trip.find(params[:trip_id])
#location = trip.locations.find(params[:id])
#location.destroy
respond_to do |format|
format.html { redirect_to trip_locations_url, notice: 'Location was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_trip
trip = Trip.find(params[:trip_id])
end
# def set_location
# trip = Trip.find(params[:trip_id])
# #location = trip.locations.find(params[:id])
# # #location = Location.find(params[:id])
# end
# post = Post.find(params[:post_id])
# #2nd you retrieve the comment thanks to params[:id]
#
# #comment = post.comments.find(params[:id])
#
# Never trust parameters from the scary internet, only allow the white list through.
def location_params
params.require(:location).permit(:name, :image, :street_address_1, :street_address_2, :city, :state, :zip_code, :country_code, :trip_id)
end
end
Nav-tab
view/nav/_tabs.html.slim
- if can?(:read, #trip)
- controller = params[:controller].singularize
ul.nav.nav-tabs#tabs
li class=('active' if params[:action] == 'show')
= link_to 'Trip', trip_path(#trip)
li class=('active' if params[:action] == 'index')
= link_to 'Location', trip_locations_url(#trip)
li class=('active' if params[:action] == 'inex')
= link_to 'Members'
li class=('active' if params[:action] == 'index')
= link_to 'Events'
li class=('active' if params[:action] == 'index')
= link_to 'Status'
location index view
header.intro-location
.intro-body
.container
.row
.col-md-18
h1.brand-heading
= render 'nav/tabs'
h1.space-above Locations
-if can?(:create, #locations)
= link_to "Add New Location", new_trip_location_path, class: 'btn btn-xs btn-primary space-right'
table.table.table-striped-location.table-hover-location.space-above
thead
tr
th Name
th Image
th Street address 1
th Street address 2
th City
th State
th Zip code
th Country code
th
th
th
tbody
- #locations.each do |location|
tr
td = location.name
td = location.image
td = location.street_address_1
td = location.street_address_2
td = location.city
td = location.state
td = location.zip_code
td = location.country_code
td = link_to 'Show', trip_location_url(location.trip, location), class: 'btn btn-xs btn-success space-right'
td = link_to 'Edit', edit_trip_location_url(location.trip, location), class: 'btn btn-xs btn-primary space-right'
td = link_to 'Destroy', [location.trip, location], data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-xs btn-danger space-right'
trip show view
p#notice = notice
header.intro-location
.intro-body
.container
.row
.col-md-14
h3.brand-heading
= render 'nav/tabs'
.col-md-6.h4
table.table.table-striped-location.table-hover-location.space-above
thead
tr
th Name:
td.show = #trip.name
tr
th Description:
td.show = #trip.description
=> link_to 'Edit', edit_trip_path(#trip), class: 'btn btn-xs btn-primary space-right'
'|
=< link_to 'Back', trips_path, class: 'btn btn-xs btn-info space-right'
Updated the nav-bar
- if can?(:read, #trip)
- controller = params[:controller].singularize
ul.nav.nav-tabs#tabs
li class=('active' if params[:action] == 'show')
= link_to 'Trip', trip_path(#trip)
li class=('active' if params[:action] == 'index')
= link_to 'Location', trip_locations_url(#trip)
li class=('active' if params[:action] == 'inex')
= link_to 'Members'
li class=('active' if params[:action] == 'index')
= link_to 'Events'
li class=('active' if params[:action] == 'index')
= link_to 'Status'
Added #trip to location/index controller
class LocationsController < ApplicationController
def index
#trip = Trip.find(params[:trip_id])
trip = Trip.find(params[:trip_id])
#locations = trip.locations
# #locations = trip.locations
end
I have been trying to figure out adding comments without reloading the page using Ajax, after reading few different tutorials this is what I came up to so far, and it's not working:
inside user_comments/_comments.html.erb
<div id="comment_form">
<%= simple_form_for [#commentable, #comment], :html => { :multipart => true }, :remote => true do |f| %>
<div class="picture"><%= image_tag current_user.avatar.url(:thumb) %></div>
<%= f.input :content, label: false, :placeholder => "Add Comment", :input_html => { :rows => 4 } %>
<%= f.submit "Add Comment" %>
<% end %>
</div>
Inside the controller:
def create
#users = User.all
#comment = #commentable.user_comments.new(params[:user_comment])
#comment.user_id = current_user[:id]
##commentable.user_comments.create(:user_id => current_user[:id])
if #comment.save
flash[:notice] = "Successfully created comment."
respond_to do |format|
format.html { redirect_to #commentable }
format.js
#format.js #{ render 'create.js.erb' }
end
else
render :new
end
end
and inside the create.js.erb
// Display a Javascript alert
<% if remotipart_submitted? %>
$("#comments_list").append("<%= escape_javascript(render(:partial => 'user_comments/comments')) %>");
<% end %>
I'm using a Gem called: remotipart
I don't know what I'm missing in the process.
in the console I get:
POST http://localhost:3000/assignments/2/user_comments
200 OK
134ms
which means the post goes through, but the comment doesnt get added back to the partial.
Ok after 2 days! I fixed it, here is what I can share and might help:
1- make sure to include the :remote => true to the form that is about to be submitted
2- Check the controller and see what the Create action is being redirected, in my case I changed to this:
def create
#users = User.all
#comment = #commentable.user_comments.new(params[:user_comment])
#comment.user_id = current_user[:id]
##commentable.user_comments.create(:user_id => current_user[:id])
if #comment.save
flash[:notice] = "Successfully created comment."
respond_to do |format|
format.html
format.js {#comments = #commentable.user_comments}
end
else
render :new
end
end
Then make sure the create.js.erb is written properly:
$("#comments_list").empty()
$("#comments_list").append("<%= escape_javascript(render(:partial => 'comments')) %>");
there you go! I hope some creates a proper tutorial for newbies like me :)!
I'm getting an error: No route matches {:action=>"sort", :controller=>"links"}
I'm adapting from a non-nested example and am having trouble figuring out the nested routing.
Right now, my route looks like this:
resources :groups do
resources :navbars do
resources :links do
collection { post :sort }
end
end
post :add_user, on: :member
end
I am rendering a collection of links from navbar>show:
= render partial: 'links/link', collection: #navbar.links
and here's the collection, links>_link.html.haml:
%ul#links{"data-update-url" => sort_group_navbar_links_url}
- #links.each do |faq|
= content_tag_for :li, link do
%span.handle [drag]
= link.method_name
= link.code
= link.button
= link.text
= link_to 'Edit Link', edit_group_navbar_link_path(#group, #navbar, link), class: 'btn btn-mini'
= link_to 'Delete', group_navbar_link_path(#group, #navbar, link), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-mini'
My links_controller has the sort action:
def sort
params[:link].each_with_index do |id, index|
Link.update_all({display_order: index+1}, {id: id})
end
render nothing: true
end
Because my link collection is being rendered from the navbar>show page, it's not clear to me where my sort action should be located (in links_controller or in navbars_controller).
And my navbars_controller defines #links:
def show
#links = #navbar.links.order("display_order")
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #navbar }
end
end
Also here's the js for good measure (links.js.coffee):
jQuery ->
$('#links').sortable
axis: 'y'
handle: '.handle'
update: ->
$.post($(this).data('update-url'), $(this).sortable('serialize'))
Maybe this last line also needs work to include the route?
I'm using rails 3.2.
I just wrote controller for ajax call like this:
def create
#like = Like.new(params[:like])
post = params[:like][:post_id]
uid = params[:like][:ip_address]
#extant = Like.find(:last, :conditions => ["post_id ? AND ip_address = ?", post, uid])
last_like_time = #extant.created_at unless #extant.blank?
curr_time = Time.now
if ((#extant && curr_time - last_like_time >= 24.hours) || #extant.blank?)
respond_to do |format|
if #like.save
format.js
format.html { redirect_to :back }
else
format.html { redirect_to posts_path }
format.json { render :json => #like.errors, :status => #unprocessable_entity }
end
end
else
render :js => "alert('You already liked this.');"
end
end
And this is view erb.
<%= form_for(#like, :remote => true) do |f| %>
<%= f.hidden_field "post_id", :value => #post.id %>
<%= f.hidden_field "ip_address", :value => request.remote_ip %>
<%= submit_tag "Like" %>
<% end %>
And it executes SQL command like this:
SELECT "likes".* FROM "likes" WHERE (post_id '1' AND ip_address = '127.0.0.1') ORDER BY "likes"."id" DESC LIMIT 1
It causes SQL syntax error. I think my ruby syntax is wrong, so how can I fix?
Change your ruby code from this:
"post_id ? AND ip_address = ?"
to
"post_id = ? AND ip_address = ?"
module UsersHelper
# Returns the Gravatar (http://gravatar.com/) for the given user.
def gravatar_for(user, options = { size: 10 })
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
size = options[:size]
gravatar_url = "http://gravatar.com/avatar/#{gravatar_id}.png?s=#{size}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
I have used this code and assumed it would vary the size of the gravatar, however it seems to have no affect on it? Am I missing something? I have also tried to change the value in the view to:
<%= gravatar_for #user, size: 10 %>
<%= #user.name %>
To see if this changes anything, to no avail.
assuming your helper module is as below
module UsersHelper
# Returns the Gravatar (http://gravatar.com/) for the given user.
def gravatar_for(user, options = { size: 50 })
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
size = options[:size]
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
then pass in your size in the view
<%= gravatar_for #user, :size => 30 %>