undefined method `item_path' while working with ajax - javascript

Im trying to update my create item action to work with Ajax but Im getting an error of undefined methoditem_path` which i wasn't getting before when it was responding in regular html format. The item is created and saved but ajax doesn't seem to work properly though.
Here is my _from partial :
<%= form_for [#user, item], remote: true do |f|%>
<div class="form-group">
<%= f.label :name, class: 'sr-only' %>
<%= f.text_field :name , class: 'form-control', placeholder: "Enter a new item " %>
</div>
<%= f.submit "Submit Item", class: 'btn btn-primary pull-right' %>
<% end %>
item#create:
def create
#item = Item.new(item_params)
#item.user = current_user
if #item.save
flash[:notice] = 'Item saved successfully.'
else
flash[:alert] = 'Item not saved. Title is too short or missing. Please try again.'
end
respond_to do |format|
format.html
format.js
end
end
create.js.erb:
$('.js-items').prepend("<%= escape_javascript(render(#item)) %>");
$('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: {user: #user , item: #item }) %>");
User#show view
<div class='new_item'>
<%= render :partial => 'items/form', :locals =>{:item => Item.new , :user => #user} %>
</div>
<div class='js-items'>
<%= render #user.items %>
</div>
routes:
user_items GET /users/:user_id/items(.:format) items#index
POST /users/:user_id/items(.:format) items#create
new_user_item GET /users/:user_id/items/new(.:format) items#new
edit_user_item GET /users/:user_id/items/:id/edit(.:format) items#edit
user_item GET /users/:user_id/items/:id(.:format) items#show
PATCH /users/:user_id/items/:id(.:format) items#update
PUT /users/:user_id/items/:id(.:format) items#update
DELETE /users/:user_id/items/:id(.:format) items#destroy
The error im getting in rails s :
ActionView::Template::Error (undefined method `item_path' for #<#<Class:0x007fa4f0d30cd8>:0x007fa4f31b26b0>):
1: <%= form_for [#user, item], remote: true do |f|%>
2: <div class="form-group">
3: <%= f.label :name, class: 'sr-only' %>
4: <%= f.text_field :name , class: 'form-control', placeholder: "Enter a new item " %>
app/views/items/_form.html.erb:1:in `_app_views_items__form_html_erb__331698480542899910_70173200751480'
app/views/items/create.js.erb:2:in `_app_views_items_create_js_erb___3618987352886002527_70173200313760'
app/controllers/items_controller.rb:17:in `create'

Do something like that.
<%= form_for [#user, item], user_items, remote: true do |f|%>
If it doesn't work then run
rake routes
in terminal see what's your path.

Related

How to avoid sending params of fields deleted using JQuery remove()

In this code I was trying to remove fileds for nested_attributes using ajax :remote => ture to avoid reloading
the whole page in browser. Although fileds in fields_for was removed from DOM and association was removed from database, the fields of the nested attributes
still exist in page source and raise ActiveRecord::RecordNotFound error when trying to send params to update action of parent model
consider the following code:
_artist_form.html.erb
<%= form_for #artist do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br/>
<%= f.label :style %>
<%= f.text_field :style %><br/>
<%= f.fields_for :songs do |song_builder|%>
<div id = 'song_<%= song_builder.object.id %>_div'>
<%= song_builder.label :title %>
<%= song_builder.text_field :title %><br/>
<%= song_builder.label :lyrics %>
<%= song_builder.text_area :lyrics %><br/>
<%= link_to 'Remove song', delete_song_path(:a_id => #artist.id, :s_id => song_builder.object.id),
:method => :delete , :remote => true %>
</div>
<% end %>
<%= f.submit 'Save' %>
<% end %>
routes.rb
Rails.application.routes.draw do
...
delete '/artists/remove_song', :to => 'artists#delete_song', :as => :delete_song
end
application_controller.rb
class ArtistsController < ApplicationController
def edit
...
end
def update
#artist = Artist.find(params[:id])
if #artist.update(artist_params) #=> error Couldn't find Song with ID=2 for Artist with ID=2
redirect_to artist_path(#artist)
else
flash[:errors] = #artist.errors.full_messages
render :edit
end
end
...
def delete_song
#song_id = params[s_id]
aritst = Artist.find(:params[a_id])
song = artist.songs.find(#song_id)
song.delete
respond_to do |format|
format.js {render 'delete_song.js.erb'}
end
end
end
delete_song.js.erb
$('#song_<%= #song_id %>_div').remove() ;
Error
Couldn't find Song with ID=2 for Artist with ID=2
how to prevent sending params of removed fields by $(...).remove() to update action?
I tried to find a solution for this error. So according to charlietfl comment, I tried to store delete status somewhere locally, then rails can delete association later. So I modified the code as following:
deleting all remote script code including delete_song.js.erb file and delete_song action and delete route. then I allowed marking nested attribute for delete in Artist model file:
accepts_nested_attributes_for :songs, :allow_destroy => true
then adding delete button in _artist_form.html.erb file as following:
<%= button_tag 'x' , :class => 'close_sign', :type => 'button', :onclick => "$('#song_#{song_builder.object.id}_destroy').val('true'); $('#song_#{song_builder.object.id}_div').hide()" %><br/>
and a hidden flied to fields_for as below:
<%= song_builder.hidden_field :_destroy, :id => "song_#{song_builder.object.id}_destroy" %>
and allowing :songs_nested_attributes => [:title, :lyrics, :_destroy] in song_params
once user remove the song field, it will be hidden and marked for destroy later

How do I render a partial containing a form_for for an edit function?

I have a div in a parent view that renders a show partial. In this show partial, I have a button that should change the parent's partial to render the 'form' partial to edit the object, but I keep getting jammed up because it seems that the 'form' partial's form_for is missing the #project object.
How can I pass this object to the 'form' partial? Am I missing something else?
I am rather new to using AJAX. Happy to provide more information if you need.
The error I am getting in the server terminal is
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
routes.rb
get 'switchProjectView', to: 'projects#switch_main_view'
resources :projects
projects_controller.rb
class ProjectsController < ApplicationController
def new
#project = Project.new
end
def create
#project = Project.new(project_params)
if #project.save
flash[:success] = "New Project Added"
redirect_to #project
else
flash[:danger] = "Project Not Added. Please Try Again"
end
end
def show
#project = Project.find(params[:id])
end
def index
#projects = Project.all
end
def update
#project = Project.find(params[:id])
if #project.update_attributes(project_params)
redirect_to #project
else
render 'edit'
end
end
def edit
end
def switch_main_view
respond_to do |format|
format.html
format.js
end
end
def project_params
params.require(:project).permit(:main_contact_name, :id, :main_contact_phone, :main_contact_email, :project_name)
end
end
show.html.erb
<div class="body">
<div class="center jumbotron heading-jumbo">
<h1><%= #project.project_name %></h1>
</div>
<div class="body-jumbo jumbotron" id='project-details'>
<%= render "projects/show" %>
</div>
</div>
switch_main_view.js.erb
$('#project-details').html("<%= j render :partial => 'projects/form' %>");
_form.html.erb
<%= form_for(#project) do |f| %>
<%= f.label :project_name %>
<%= f.text_field :project_name, class: 'form-control'%>
<%= f.label :main_contact_name %>
<%= f.text_field :main_contact_name, class: 'form-control'%>
<%= f.label :main_contact_phone %>
<%= f.text_field :main_contact_phone, class: 'form-control'%>
<%= f.label :main_contact_email %>
<%= f.text_field :main_contact_email, class: 'form-control'%>
<%= f.submit 'Save Project', class: 'btn btn-primary'%>
<% end %>
_show.html.erb
<div class='text-center center'>
<h3><strong>Project Information</strong></h2>
</div>
<h2>Start Date: Launch Date:</h1>
<span class='pull-right jumbo-btn-span'><%= link_to "Edit Project Information", switchProjectView_path(#project), remote: true, class:'btn btn-primary jumbo-btn' %></span>
<h2>Primary Conact's Name: <%= #project.main_contact_name %></h2>
<h2>Primary Conact's Phone: <%= #project.main_contact_phone %></h2>
<h2>Primary Conact's Email: <%= #project.main_contact_email %></h2>
Well, with each request, you need to re-initialize the variable in your controller method. In your case, you need to do the following:
def switch_main_view
#project = Project.new
respond_to do |format|
format.html
format.js
end
end
Doing so will enable you to get rid of the error: First argument in form cannot contain nil or be empty, but that won't enable you to do what you are actually trying to do.
When you use link_to, by default it goes for an HTML request as you can see in Rails logs, something like following will appear:
Processing by ProjectsController#switch_main_view as HTML
In order to get the JS response, you need to tell link_to that you are up for a JS response, not for an HTML response, and you can do by passing format: :js in link_to like:
<%= link_to "Edit Project Information", switchProjectView_path(#project, format: :js), remote: true, class:'btn btn-primary jumbo-btn' %></span>
remote: true will be there to make sure that you aren't reloading the contents of the page, rather you are trying to fetch something from the server in the background.
Your request "switchProjectView_path(#project)" only send object id to server, so you need to load the object to present it in view for response.
1. First the route should look like this so that, the url could contain object id:
get 'switchProjectView/:id', to: 'projects#switch_main_view', as:"switchProjectView"
2. You have to load the object in controller:
def switch_main_view
#project = Project.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
Try passing the variable when calling the partial:
$('#project-details').html("<%= j render :partial => 'projects/form', locals: {project: #project} %>");

Unpermitted parameter: songs_attributes

I have a problem with my nested attributes. I want someone to be able to just visit my website and add songs to an event. They can only add those songs if they supply a partycode for that event. I have my nested attributes set up correctly I think but I am getting an unpermitted paramter error.
Events controller:
class EventsController < ApplicationController
def new
#event = Event.new
#event.songs.build
end
def show
#event = Event.find(params[:id])
#songs = #event.songs.paginate(page: params[:page])
end
def create
#event = current_user.events.build(event_params)
if #event.save
flash[:success] = "Event Created!"
redirect_to user_path(#event.user)
else
render 'welcome/index'
end
end
def destroy
end
private
def event_params
params.require(:event).permit(:name, :partycode, song_attributes: [:artist, :title, :genre, :partycode])
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include SessionsHelper
end
Here is the new.html.erb file in the songs view, which contains the code to add songs to the event, note that the user is not signed in when they are adding songs:
<br>
<br>
<div class ="container">
<div class="jumbotron">
<%= form_for Event.new do |f| %>
<h3>Enter a song:</h3>
<%= f.fields_for :songs, Song.new do |song_form| %>
<%= song_form.collection_select(:event_id, Event.all, :id, :name) %>
<%= song_form.text_field :artist, placeholder: "Artist" %>
<%= song_form.text_field :title, placeholder: "Title" %>
<%= song_form.text_field :genre, placeholder: "Genre" %>
<% end %>
<%= link_to_add_fields "Add Song", f, :songs %>
<%= f.text_field :partycode %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
The link_to_add_fields method is in the application_helper.rb file:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render("songs_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
The songs_field partial is defined as follows:
<fieldset>
<%= f.text_field :artist, placeholder: "Artist" %>
<%= f.text_field :title, placeholder: "Title" %>
<%= f.text_field :genre, placeholder: "Genre" %>
</fieldset>
The coffee-script that adds the fields:
$(document).on 'click', 'form .add_songs', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('event_id'), 'g')
$(this).before($(this).data('songs').replace(regexp, time))
event.preventDefault()
The person from the new.html.erb page will be able to select a event from the drop down menu then on demand add more fields that are for a song and then enter a partycode for the certain event that they picked. Any help on this would be fantastic! Thanks
EDIT error:
undefined method `events' for nil:NilClass
In your EventsController, your nested params is spelled as song_attributes in event_params method
private
def event_params
params.require(:event).permit(:name, :partycode, song_attributes: [:artist, :title, :genre, :partycode])
end
But your error says unpermitted parameter: songs_attributes.
You spelled it incorrect.Change your event_params method in EventsController as follows
private
def event_params
params.require(:event).permit(:name, :partycode, songs_attributes: [:artist, :title, :genre, :partycode])
end

Why is the link_to submitting form twice?

I am trying to use JavaScript with jquery in rails to update a div without reloading the page. Its working but the comment is being created twice. I know something is wrong in the form partial but couldn't figure it out. Any help?
The following are the files -
_new_comment.html.erb
<%= form_for [:home, Comment.new], :url => home_comments_path, :html => {:id => "comment-new-" + post.id.to_s} do |f| %>
<div>
<%= f.text_area :message, :class => "message-area-" + post.id.to_s, :placeholder => "Add comment..." %>
<%= f.hidden_field :post_id, :value => post.id %>
<span class="new-comment"><%= link_to 'Add', '#', remote: true, :onclick => "$('#comment-new-#{post.id}').submit()" %></span>
</div>
<% end %>
comments_controller.rb
def create
#comment = Comment.new(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:notice] = 'Comment added sucessfully'
respond_to do |format|
format.html { redirect_to home_posts_url }
format.js
end
end
end
create.js.erb
$("#comment-new-83").before('<div class="notice"><%= escape_javascript(flash[:notice]) %></div>');
$("#comment-new-83")[0].reset();
home.js
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
$(document).ready(function() {
$("#comment-new-83").submit(function() {
$.post($(this).attr("action"), $(this).serialize(), null, "script");
return false;
})
})
form_for will automatically post to the controller. You need not submit the form explicitly using jquery.
Reference

jQuery Tokeninput Error in Rails

I'm trying to use jQuery Tokeninput as shown in Railscast #258 (revised). When I enter something in the tokeninput field, the field does not dropdown with results and I get the following javascript error: Uncaught TypeError: Cannot call method 'replace' of undefined.
My json data works fine when I do a manual query on it, and the server request looks fine. I am trying to search the content column in my issues table, so I set propertyToSearch to "content".
Here is my code:
coffeescript:
jQuery ->
$('#fact_issue_tokens').tokenInput "/issues.json"
theme: 'facebook'
zindex: 11001
propertyToSearch: 'content'
tokenValue: 'content'
hintText: 'Enter an issue'
preventDuplicates: true
Issue Model:
def self.tokens(query)
issues = where("content like ?", "%#{query}%")
if issues.empty?
[{id: "<<<#{query}>>>", content: "New: \"#{query}\""}]
else
issues
end
end
def self.ids_from_tokens(tokens)
tokens.gsub!(/<<<(.+?)>>>/) { create!(content: $1).id }
tokens.split(',')
end
Issues Controller:
def index
#issues = Issue.order(:content)
respond_to do |format|
format.html
format.json { render json: #issues.tokens(params[:q]) }
end
end
Form:
<%= form_for(Fact.new, :url => kase_facts_path(current_kase), :html => {:class => "form-
inline"}) do |f| %>
<%= f.text_field :page, placeholder: 'Page' %>
<%= f.text_field :description, placeholder: 'Description' %>
<%= f.label :issue_tokens, 'Issue tags' %>
<%= f.text_field :issue_tokens %>
<%= f.hidden_field :source_id, :value => #source.id %>
<%= f.submit 'Add Fact' %>
<% end %>
#Scott you try this
jQuery ->
$('#fact_issue_tokens').tokenInput '/issues.json'
theme: 'facebook'
tokenLimit: 5
minChars: 4
preventDuplicates: true
searchingText: "Enter an issue..."
prePopulate: $('#fact_issue_tokens').data('load')
and think on your index because you are using (:content) not name might be your problem. I am bot sure why but i used title and i had a problem, i thought it was mysql or something.
When you visit
http://localhost:3000/issues.json
Do you get the JSON data?
Edit.
Can you please try this for your form?
<div class="field">
<%= f.label :issue_tokens, "Issues" %><br />
<%= f.text_field :issue_tokens, data: {load: #fact.issues} %>
</div>

Categories

Resources