I tried to use Ajax request for creating a new object and this had been working very well. In my view file I used to set remote: true option for link_to and everything was fine.
Now I want to render my _form partial once the view file is loaded without a link, but just using a <%= render 'form' %>.
I don't understand why I am getting this error. Who can enlighten me what am I doing wrong?
views/tasks/index.html
<h3>Tasks database</h3>
<table>
<% #tasks.each do |task| %>
<tr class='tasks' id="task_<%= task.id %>">
<td>
<%= link_to user_task_path(current_user, task.id), method: :delete,
data: { confirm: 'Are you sure?' }, remote: true do %>
<i class="glyphicon glyphicon-trash"></i>
<% end %>
<a href="#" data-xeditable="true" data-pk="task" data-model='task' data-name='title'
data-url="/users/<%= current_user.id %>/tasks/<%= task.id %>" data-title="Enter title">
<i><%= task.title %></i>
</a>
</td>
</tr>
<% end %>
<tr>
<td><%= render 'form' %></td>
</tr>
</table>
controllers/tasks_controller.rb
class TasksController < ApplicationController
before_filter :authorize, only: [:edit, :new, :destroy]
def index
#tasks = current_user.tasks
end
def show
#task = Task.find(params[:id])
redirect_to users_path
end
def edit
#task = Task.find(params[:id])
end
def new
#task = Task.new
end
def create
#task = current_user.tasks.new(task_params)
respond_to do |format|
if #task.save
format.html { redirect_to user_tasks_path(current_user) }
format.js
else
format.html { render action: 'new' }
format.js
end
end
end
def update
#task = Task.find(params[:id])
respond_to do |format|
if #task.update(task_params)
format.html { redirect_to user_tasks_path(current_user), notice: 'Post successfully was updated.'}
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { head :no_content }
end
end
end
def destroy
#task = Task.find(params[:id])
#task.destroy
respond_to {|format| format.js }
end
private
def task_params
params.require(:task).permit(:title)
end
end
views/tasks/_form.html
<%= form_for [current_user, #task], remote: true do |f| %>
<%= f.text_field :title %>
<%= f.hidden_field :user_id, value: params[:user_id] %>
<%= f.submit %>
<% end %>
views/tasks/create.js
$('#new_task').remove();
$('#new_link').show();
$('.tasks').last().after("<%=j render partial: 'task', :locals => { :task => #task } %>");
setXeditable();
Here is my rake routes
Any help?
First argument in form cannot contain nil or be empty
You are rendering form in index page and you didn't set #task in index method.
You should set #task in index method
def index
#tasks = current_user.tasks
#task = Task.new
end
Related
When you change the items in the form of an artifact appears , help me to understand what is the reason ?
view project#show:
<div class="container">
<h3><%= #project.name %></h3>
<h2>Tasks</h2>
<table class="table table-striped" id="tasks_list">
<%= render #project.tasks %>
</table>
<h2>Add a task:</h2>
<%= render 'tasks/form' %>
<%= link_to 'Back', projects_path %>
</div>
screenshot#1
If you change tasks list and add from:
<div class="container">
<h3><%= #project.name %></h3>
<h2>Add a task:</h2>
<%= render 'tasks/form' %>
<h2>Tasks</h2>
<table class="table table-striped" id="tasks_list">
<%= render #project.tasks %>
</table>
<%= link_to 'Back', projects_path %>
</div>
screenshot#2
Task list size has not changed - but there was a strange artifact.
Update
view task#_form.html.erb:
<%= form_for([#project, #project.tasks.build], remote: true) do |f| %>
<div class="input-group">
<div aria-describedby="add_project">
<%= f.text_field :name, class: 'form-control ' %>
</div>
<span class="input-group-btn">
<%= f.submit 'Добавить', class: 'btn btn-success btn-secondary', id: "add_project" %>
</span>
</div>
<% end %>
Task Controller:
def create
#project = Project.find(params[:project_id])
#task = #project.tasks.create(task_params)
respond_to do |format|
if #task.save
format.html { redirect_to #project, notice: 'Task was successfully created.' }
format.js {}
format.json { render json: #task, status: :created, location: #task }
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
def destroy
#task = Task.find(params[:id])
#task.destroy
respond_to do |format|
format.html { redirect_to products_path, success: 'Task destroyed successfully' }
format.js {}
end
end
private
def task_params
params.require(:task).permit(:name)
end
Project Controller:
def index
#projects = Project.all
#project = Project.new
end
def show
#project = Project.find(params[:id])
end
def edit
#article = Project.find(params[:id])
end
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.js {}
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: 'new' }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
Added to the form: <%= form_for([#project, #project.tasks.klass.build], remote: true) do |f| %>
Now error:
NoMethodError in Projects#show
Showing /Users/alexandr.dmitrenko/todolist/app/views/tasks/_form.html.erb where line #1 raised:
undefined method `build' for #<Class:0x007ffde19efea8>
Extracted source (around line #1):
1<%= form_for([#project, #project.tasks.klass.build], remote: true) do |f| %>
The reason is this bit:
#project.tasks.build
in your form. What it does it builds a new, non-saved Task record and stores it within association. Every further call to #project.tasks will return the usual results (from database) + this new record. What you need to do is to replace it with:
#project.tasks.scope.build
scope method will return new instance of the association, so it is safe to call build on it as it will not be stored anywhere and won't affect your original association object.
I have a model called Images with an uploader attached to it (Carrierwave). Images belongs to a model called Listing. After creating a listings I'm redirected to the Images index page to upload files (localhost:3000/listings/1/images)
But for some reason every time I create a listing an image it's created at the same time. There's actually no image present but it displays the "delete" link I have for each image.
<span><%= link_to 'DELETE', listing_image_path(#listing, image.id), data: { confirm: 'Are you sure?' }, :method => :delete, :class => 'delete' %></span>
Any help? Thanks.
Listings Controller
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, :except => [:show, :index]
def index
#listings = Listing.order('created_at DESC')
respond_to do |format|
format.html
format.json { render json: #listings }
end
end
def show
end
def new
#listing = Listing.new
#listing.user = current_user
end
def edit
end
def create
#listing = Listing.new(listing_params)
#listing.user = current_user
respond_to do |format|
if #listing.save
format.html { redirect_to listing_images_path(#listing), notice: 'Post was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #listing.update(listing_params)
flash[:notice] = 'Deal was successfully updated.'
format.html { redirect_to #listing }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:id, :condition, :description, :nickname, :price, :size, :title, :user_id)
end
end
Listings Form
<%= form_for(#listing, :html => { :class => 'form', :multipart => true }) do |f| %>
<% if #listing.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#listing.errors.count, "error") %> prohibited this listing from being saved:</h2>
<ul>
<% #listing.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= f.label :title %>
<%= f.text_field :title, :required => true %>
</div>
<div>
<%= f.label :price %>
<%= f.text_field :price %>
</div>
<div class="actions">
<%= f.submit 'Submit', :class => 'buyNow' %>
</div>
<% end %>
Images Controller
class ImagesController < ApplicationController
before_action :set_image, only: [:show, :edit, :update, :destroy]
before_filter :load_listing
def index
#images = #listing.images.load
#image = #listing.images.new
end
def new
end
def edit
end
def create
#image = #listing.images.new(image_params)
respond_to do |format|
if #image.save
format.html { redirect_to :back, notice: 'Image was successfully created.' }
format.json { head :no_content }
else
format.html { render action: 'new' }
format.json { render json: #image.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #image.update(image_params)
format.html { redirect_to (#image.listing), notice: 'Image was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #image.errors, status: :unprocessable_entity }
end
end
end
def destroy
#image = #listing.images.find(params[:id])
#image.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_image
#image = Image.find(params[:id])
end
def load_listing
#listing = Listing.find(params[:listing_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def image_params
params.require(:image).permit(:file, :listing_id)
end
end
Images Index
<div>
<%= form_for [#listing, #image], :html => { :class => 'uploadImages', :multipart => true } do |f| %>
<%= f.hidden_field :listing_id %>
<div>
<%= f.label :file, 'Upload Images' %>
<%= f.file_field :file, multiple: true, name: 'image[file]' %>
</div>
<% end %>
</div>
<div id="progress"></div>
<% if #images.present? %>
<ul class="editGallery">
<% #listing.images.each do |image| %>
<li>
<%= image_tag image.file_url(:list) if image.file? %>
<span><%= link_to 'DELETE', listing_image_path(#listing, image.id), data: { confirm: 'Are you sure?' }, :method => :delete, :class => 'delete' %></span>
</li>
<% end %>
</ul>
<% end %>
The problem is this line:
#image = #listing.images.new
That's building a new image for #listing, so when you call #listing.images.each that new image is included in the images array. Check that the image has actually been saved to the database before constructing a delete link for it.
<% #listing.images.each do |image| %>
<% unless image.new_record? %>
<li>
<%= image_tag image.file_url(:list) if image.file? %>
<span><%= link_to 'DELETE', listing_image_path(#listing, image.id), data: { confirm: 'Are you sure?' }, :method => :delete, :class => 'delete' %></span>
</li>
<% end %>
<% end %>
Take a look at this part of your code:
<% if #images.present? %>
<ul class="editGallery">
<% #listing.images.each do |image| %>
<li>
<%= image_tag image.file_url(:list) if image.file? %>
<span><%= link_to 'DELETE', listing_image_path(#listing, image.id), data: { confirm: 'Are you sure?' }, :method => :delete, :class => 'delete' %></span>
</li>
<% end %>
</ul>
I believe your problem is a combination of this and your images controller index action.
When you hit the index action you create a new record #image = #listing.images.new
Now your #listing.images.each call registers on the object that hasn't been saved.
How do I get this page to paginate using kaminari? I need help with this badly. I don't know what to do. Just get me some way so that all the posts will only be 15 per page. I want the show page to be paginated not the index page.
This is the website I built.
http://duelingpets.net/maintopics/9/subtopics/4
This is my show page for my subtopics page that is nested under maintopics
<p id="notice"><%= notice %></p>
This pages shows the current topic name of a subtopic
<h1 class="forumheader"><%= #subtopic.topicname %></h1>
<br><!---Gives space to start the narratives--->
<div class="narrativecontainer">
<table>
<tr>
<td><%= #subtopic.topicname %></td>
</tr>
<tr>
<td>by: <%= #subtopic.user.vname %></td>
</tr>
<tr>
<td><pre class="narrative_pre"><%= #subtopic.description %></pre></td>
</tr>
</table>
<br>
<% #subtopic.narratives.each do |narrative| %>
<div class="outer">
<table>
<tr>
<td>re:<%= narrative.subtopic.topicname %></td>
<% if current_user && (current_user.id == narrative.user_id || current_user.admin?)%>
<td><%= button_to 'Edit', edit_subtopic_narrative_path(#subtopic, narrative), method: :get %></td>
<td><%= button_to 'Destroy', [#subtopic, narrative], method: :delete, data: { confirm: 'Are you sure?' } %></td>
<% end %>
</tr>
<tr>
<td>by: <%= narrative.user.vname %><%#= subtopic.description %></td>
</tr>
</table>
</div>
<div class="outer">
<pre class="narrative_pre"><%= narrative.story %></pre>
</div>
<br>
<% end %>
</div>
<br>
<% if current_user %>
<p><%= link_to 'New Narrative', new_subtopic_narrative_path(#subtopic) %></p>
<br>
<% end %>
<p><%= link_to 'Back', tcontainer_maintopic_path(#maintopic.tcontainer_id, #maintopic) %></p>
This my subtopics controller.
class SubtopicsController < ApplicationController
# GET /subtopics
# GET /subtopics.json
#before_filter :load_forum
before_filter :load_topic, :only => [:edit, :update, :show, :destroy]
before_filter :load_maintopic, :only =>[:create, :index, :new]
def index
if current_user && current_user.admin?
#subtopics = #maintopic.subtopics.all
else
render "public/404"
end
end
# GET /subtopics/1
# GET /subtopics/1.json
def show
##subtopic.narratives.page(params[:page])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #subtopic }
end
end
# GET /subtopics/new
# GET /subtopics/new.json
def new
if current_user
#user = current_user.id
#subtopic = #maintopic.subtopics.build
#subtopic.user_id = #user
else
redirect_to root_url
end
end
# GET /subtopics/1/edit
def edit
end
# POST /subtopics
# POST /subtopics.json
def create
if current_user
#user = current_user.id
#subtopic = #maintopic.subtopics.new(params[:subtopic])
#subtopic.user_id = #user
if !(#subtopic.maintopic_id == #maintopic.id) #Prevents a subtopic from being assigned data to a maintopic that doesn't match
redirect_to #maintopic
return
end
#subtopic.created_on = Time.now
#subtopic.save
#if #subtopic.save
# redirect_to #maintopic.subtopic
#else
# render "new";
#end
redirect_to maintopic_subtopic_path(#maintopic, #subtopic)
else
redirect_to root_url
end
end
# PUT /subtopics/1
# PUT /subtopics/1.json
def update
respond_to do |format|
if #subtopic.update_attributes(params[:subtopic])
format.html { redirect_to maintopic_subtopic_path(#subtopic.maintopic_id, #subtopic.id), notice: 'Subtopic was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #subtopic.errors, status: :unprocessable_entity }
end
end
end
#raise
# DELETE /subtopics/1
# DELETE /subtopics/1.json
def destroy
#subtopic.destroy
respond_to do |format|
format.html { redirect_to tcontainer_maintopic_path(#maintopic.tcontainer_id, #maintopic.id) }
format.json { head :no_content }
end
end
private
def load_topic
#subtopic = Subtopic.find(params[:id])
#maintopic = Maintopic.find(#subtopic.maintopic_id)
#content = Maintopic.find(params[:maintopic_id])
if #content.id != #maintopic.id
# raise "I been tampered with and should redirect to the root page"
redirect_to root_url
end
end
def load_maintopic
#maintopic = Maintopic.find(params[:maintopic_id])
end
end
in the Subtopic model add the string:
paginates_per 15
in the controller:
def index
if current_user && current_user.admin?
#subtopics = #maintopic.subtopics.page params[:page]
else
render "public/404"
end
end
and in the index view add:
<%= paginate #subtopics %>
For more information about formatting paginator go to https://github.com/amatsuda/kaminari#helpers
try this in your controller index
`#subtopics = kaminari.paginate_array(#subtopics).page(params[:page]).per(params[:per_page])`
and in your views, edit as
<%= page_entries_info #subtopics %> and also <%= paginate #subtopics, :theme => 'twitter-bootstrap-3' %>
I'm trying to add answers to questions. Each questions has_one answer. I'm showing them on the comment page through partials except I keep getting this error:
undefined local variable or method `answer'
Here is part of my answers_controller.rb
class AnswersController < ApplicationController
before_action :set_answer, only: [:show, :edit, :update, :destroy]
def index
#question = Question.find params[:question_id]
#question.answers
end
def show
end
def new
#question = Question.find params[:question_id]
end
def edit
end
def create
#question = Question.find(params[:question_id])
#answer = #question.answers.create(answer_params)
respond_to do |format|
if #answer.save
format.html { redirect_to #comment, notice: 'Answer was successfully created.' }
format.json { render action: 'show', status: :created, location: #answer }
else
format.html { render action: 'new' }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
Here is my _question.html.erb partial where the answer partial is called:
<%=div_for(question) do %>
<div class="questioncontainer">
<p>
<%= question.body %>
<%= render :partial => #question.answers %>
<% if current_user == #comment.user %>
<div class="answercontainer">
<%= link_to 'Answer', new_question_answer_path(question)%>
</div>
</div>
</p>
<% end %>
<% end %>
Last, here is my _answer.html.erb partial:
<%=div_for(answer) do %>
<div class="questioncontainer">
<p>
<%= answer.body %>
</p>
</div>
<% end %>
Thanks for the help :)
Pass answer as local, via locals: {answer: #answer}
Use
<%= render question.answers %>
instead of
<%= render :partial => #question.answers %>
More info here: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
If you take a look at the project here: http://www.leapfm.com/ you can scroll down and click More on the front page and it works. However, if you try doing that in New Songs tab it stays at 'Page is loading...'. I'm not quite sure why this is.
new_songs.html.erb
<div id="new_songs">
<%= render 'new_songs'%>
</div></div>
_new_songs.html.erb (partial)
<div id="layout-1">
<!--div class="left-side"> -->
<%#= will_paginate #songs %>
<h6>New songs</h6>
<hr>
<ol><% #songs.each do |song| %>
<span class="title">
<li><%= link_to song.title, song %><span class="subtext"> (<%= song.url %>)<br></li></span>
<%#=link_to '▼'.html_safe, vote_against_song_path(song), :remote => true, :method => :put %>
posted <%= time_ago_in_words(song.created_at) + " ago" %>
<small><span class="comments"></small> | <%= pluralize(song.comments.size, 'comment') %></span></small><br /></span>
<%#= link_to 'Show', song, class: "button small secondary" %>
<%= link_to('Edit', edit_song_path(song), class: "button small secondary") if can? :update, song %>
<%= link_to('Destroy', song, method: :delete, data: {confirm: 'Are you sure?'}, class: "button small secondary") if can? :destroy, song %>
<% end %>
</ol>
</div>
<div class="pagination-centered">
<ul class="pagination">
<%#= will_paginate #songs %>
<!-- or custom pagination -->
<% if #songs.previous_page %>
<%= link_to "Back", params.merge(page: #songs.previous_page) %>
<% end %>
<% if #songs.next_page %>
<%= link_to "More", params.merge(page: #songs.next_page) %>
<% end %>
</ul></div>
pagination.js
$(function() {
$(".pagination a").on("click", function() {
$(".pagination").html("Page is loading...");
$.getScript(this.href);
return false;
});
});
song_controller.rb
class SongsController < ApplicationController
before_filter :authenticate_user!, only: [:create ,:edit, :update, :destroy, :vote_for_song]
before_action :set_song, only: [:show, :edit, :update, :destroy, :vote_for_song]
def extract_video
#song = Song.find(params[:id])
#song.YouTubeAddy.extract_video_id
end
def vote_for
#song = Song.find(params[:id])
current_user.vote_for(#song)
#song.plusminus = #song.votes_for
#song.save
respond_to do |format|
format.js { render 'update_votes' }
end
end
def vote_against
#song = Song.find(params[:id])
current_user.vote_against(#song)
respond_to do |format|
format.js { render 'update_votes' }
end
end
def new_songs
#songs = Song.order("id DESC").paginate(:page => params[:page], :per_page => 15)
end
# GET /Songs
# GET /Songs.json
def index
if params[:genre]
#songs = Song.tagged_with(params[:genre]).paginate(:page => params[:page], :per_page => 15)
else
#songs = Song.order('plusminus').paginate(:page => params[:page], :per_page => 15)
end
end
# GET /Songs/1
# GET /Songs/1.json
def show
#comment = Comment.new(song: #song)
#video_tag = YouTubeAddy.extract_video_id(#song.url)
end
# GET /Songs/new
def new
#song = Song.new
end
# GET /Songs/1/edit
def edit
end
# POST /Songs
# POST /Songs.json
def create
#song = Song.new(song_params)
respond_to do |format|
if #song.save
format.html { redirect_to #song, notice: 'Song was successfully created.' }
format.json { render action: 'show', status: :created, location: #song }
else
format.html { render action: 'new' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /Songs/1
# PATCH/PUT /Songs/1.json
def update
respond_to do |format|
if #song.update(song_params)
format.html { redirect_to #song, notice: 'Song was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# Song /Songs/1
# Song /Songs/1.json
def destroy
#song.destroy
respond_to do |format|
format.html { redirect_to songs_url }
format.json { head :no_content }
end
end
private
def set_song
#song = Song.find(params[:id])
end
def song_params
params.require(:song).permit(:title, :artist, :url, :track, :user_id, :tag_list)
end
end
you are placing js code for 2 actions in the same file.
you have index action and new_songs action in songs_controller.rb, and you put your js in index.js.erb:
$("#songs").html("<%= escape_javascript(render("songs")) %>");
$("#new_songs").html("<%= escape_javascript(render("new_songs")) %>");
move the second line in a file called new_songs.js.erb and you are done.