How to create a new object with Ajax request? - ruby-on-rails

For example I have my index view with all objects in database. And instead of clicking on Create button I want to get it done without refreshing the page using Ajax. How to do it? How can I change my controller for this purpose? Thanks in advance.
My controller
class ArticlesController < ApplicationController
before_filter :authorize, only: [:edit, :new, :destroy]
def index
#articles = current_user.articles
end
def show
#article = Article.find(params[:id])
redirect_to users_path
end
def edit
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = current_user.articles.build(article_params)
if #article.save
redirect_to user_articles_path(current_user)
else
render 'new'
end
end
def update
#article = Article.find(params[:id])
respond_to do |format|
if #article.update(article_params)
format.html {redirect_to user_articles_path(current_user), notice: 'Post was successfully updated'}
format.json { head :no_content }
else
format.html {render action: 'edit' }
end
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
respond_to {|format| format.js }
end
private
def article_params
params.require(:article).permit(:title)
end
end

For the Ajax, you need a form/link/button with remote:true option, a controller action to handle the JS request and a corresponding view page.
#new.html.erb
<%= form_for #article, remote: true do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<% end %>
<b>List of Articles</b>
<ul id="articles">
<%= render #articles %>
</ul>
As you want it for creating the articles, change your new and create methods like below
#articles_acontroller
def mew
#article = Article.new
#articles = current_user.articles
end
def create
#article = current_user.articles.build(article_params)
if #article.save
respond_to do |format|
format.html { redirect_to user_articles_path(current_user) }
format.js
else
render 'new'
end
end
end
Add a create.js.erb file
#create.js.erb
$("<%= escape_javascript(render #article) %>").appendTo("#articles");
And a _article.html.erb to display the created articles.
<li><%= article.title %></li>

Related

undefined method `albums_path'

I dont understand why this is happening but I am getting this error.
undefined method albums_path and it says that it is on the first line in this code:
<%= form_for #album, :html => { :class => 'form-horizontal', multipart: true } do |f| %>
<div class="control-group">
<%= f.label :name, :class => 'control-label' %>
<div class="controls">
but I dont see why. here is my controller:
class AlbumsController < ApplicationController
before_action :set_album, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#user = User.find_by_id(params[:id])
#albums = Album.all.where(:user_id => #user)
end
def show
redirect_to user_albums_url
end
def new
#album = Album.new
end
def edit
end
def create
#album = current_user.albums.new(album_params)
respond_to do |format|
if #album.save
if params[:images]
params[:images].each { |image|
#album.pictures.create(image: image)
}
end
format.html { redirect_to #album, notice: 'Gallery was successfully created.' }
format.json { render json: #album, status: :created, location: #album }
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
def update
#album.update(album_params)
redirect_to user_albums_url
end
def destroy
#album.destroy
redirect_to user_albums_url
end
private
def set_album
#album = Album.find(params[:id])
end
def album_params
params.require(:album).permit(:name, :description, :images)
end
end
and my routes are as follows:
resources :users do
resources :albums do
resources :pictures do
resources :comments
end
end
end
Ive looked everywhere for my code even mentioning "albums_path" but it doesnt say it anywhere. Is there anything that you guys can think of being the problem? I've tried fixing the forms but it doesnt seem to work. another thing that you might want to see is the link to new action. here it is:
<%= link_to 'New Album', new_user_album_path(:user_id => current_user.id), :class => 'btn btn-mini' %>
I don't know if this helps at all but I'm using the paperclip gem to create albums.
Your albums resource is nested within users resource. Therefore you should set user in your new action (or, better, in before_filter):
before_filter :set_user
# ...
def set_user
#user = User.find(params[:user_id])
end
and add user reference to your form:
form_for [#user, #album] do |f|
BTW, instead of #albums = Album.all.where(:user_id => #user), you can have (it's much more idiomatic in Rails): #albums = #user.albums.

Rails many to many association

I have implemented a save buttons for jobs and it work fine now i want to list some of the saved jobs in the jobs index page for this i have this code
<h3>Saved Jobs</h3>
<ul>
<% #user.saved_jobs.limit(5).order(:created_at).reverse_order.each do |saved_job| %>
<li><%= link_to saved_job.job.title, saved_job.job.url %>
<span class="delete_button">
<%= link_to "X", saved_job, :method => :delete, :remote => true %></span></li>
<% end %>
</ul>
<%= link_to "see all", saved_jobs_path %>
but when i want access to the jobs index page i get this error undefined method saved_jobs' for nil:NilClass
this my saved_jobs controller
class SavedJobsController < ApplicationController
before_filter :authenticate_user!
def index
#saved_jobs = SavedJob.find_all_by_user_id(current_user.id)
end
def create
#job = Job.find(params[:saved_job][:job_id])
current_user.save_job!(#job)
respond_to do |format|
format.html { redirect_to #job }
format.js
end
end
def destroy
#job = SavedJob.find(params[:id]).job
current_user.saved_jobs.find(params[:id]).destroy
respond_to do |format|
format.html { redirect_to #job }
format.js
end
end
end
and this is my user controller
class ProfilesController < ApplicationController
before_filter :authenticate_user!
def show
#user = User.find_by_slug(params[:id])
if #user
#posts = Post.all
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
def index
#users = user_scope.paginate(page: params[:page], per_page: 2)
end
private
def user_scope
current_user ? User.where.not(id: current_user.id) : User.all
end
end
The error suggests that you didn't set #user in your controller action. Can you post the code from your controller?
Update based on controller code:
Your index action in SavedJobsController does not set #user. When you then call #user.saved_jobs.limit(5)..etc... in the view #user is nil, rather than current_user or whatever.
Additionally, you have set #saved_jobs - why not just use that instead of #user.saved_jobs?
for instance:
#in SavedJobsController
def index
#saved_jobs = current_user.saved_jobs.limit(5).order('created_at DESC')
end
and then, in your view:
<% #saved_jobs.each do |saved_job| %>

Ruby on Rails form_for reference class id and pass to child comment

I have a class called "questions", which is similar to an article, and each of them can have comments. Now the problem is, that I want to show multiple questions on the index page and all displaying the comments of the specific question as well as a small little form to leave a comment, which should be added to its question. Basically I have added the form and done everything, apart from figuring out how to get the question id and pass it to the comment.
I have made a little screenshot as well: http://prntscr.com/2pjk0i
questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
#current_user ||= User.find_by_id(session[:user_id])
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
# GET /questions/new
def new
#question = Question.new
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
#current_user ||= User.find_by_id(session[:user_id])
#question.update(:user_id => #current_user.id)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render action: 'show', status: :created, location: #question }
else
format.html { render action: 'new' }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :body)
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#current_user ||= User.find_by_id(session[:user_id])
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
#current_user ||= User.find_by_id(session[:user_id])
#comment.update(:user_id => #current_user.id, :question_id => ?) # What to add here to get the specific question id?
respond_to do |format|
if #comment.save
format.html { redirect_to '/', notice: 'comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to '', notice: 'comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to '' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:title, :body)
end
end
index.html.erb
<h1>Listing questions</h1>
<%= link_to 'New Question', new_question_path %>
<hr>
<% #questions.each do |question| %>
<!-- Author -->
<%= question.user.name %> <br>
<!-- Date -->
<%= question.created_at %> <br>
<!-- Title -->
<%= question.title %> <br>
<!-- Body -->
<%= question.body %> <br>
<%= question.id %> <br>
<!-- Comment count -->
<%= question.comments.size %> Comment <br>
<!-- Comments -->
<% question.comments.each do |comment| %>
<!-- Comment Author -->
<%= comment.user.name %> <br>
<!-- Comment Date -->
<%= comment.created_at %> <br>
<!-- Comment Body -->
<%= comment.body %> <br>
<% end %>
<%= form_for(question.comments.new) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<hr>
<% end %>
Thank you in advance for your help! :)
The form_for will need to submit the question_id somehow - either by a route or through the form. I recommend a route.
If you don't interact with comments independently - if there is always a question, then change your routes to something like this:
resources :questions do
resources :comments
end
Then - in your form for, you will do this
<%= form_for [question, question.comments.new] do |f| %>
This will cause the form to submit (POST) to /question/:question_id/comments and you can handle it from there.
In the comments controller - you'll get the question from the params[:question_id] and return the result via an ajax response (respond to json).
This part is still tricky if you haven't done it before. If you need help with that part, you can probably find good examples or ask a separate question...
you can add hidden field inside your form
<%= f.hidden_field :question_id, value: question.id %>
or you can change your form
<%= form_for :comment, :url => comments_path(question_id:question.id) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
when u submit this form u will have url like /comments?question_id=id

Using <%= render comments %> always outputs an empty partial, even if there is nothing in the database

I'm starting to wonder if this is a bug with Rails 4, but I'm very new to rails and find myself smacking myself in the forehead eventually with most of the bugs I run in to. But I'm running into a wall on this one.
I have a Post. Posts have comments.
My Comment partial (/views/comments/_comment.html.erb)
<div class="comment-wrap">
<div class="row">
<div class="comment-meta">
<%= comment.commenter %>
<small><%= comment.created_at %></small>
<%= link_to 'Destroy', [comment.post, comment], method: :delete, confirm: 'Are you sure?', class: "tiny button radius right" %>
</div>
<div class="small-2 columns">
<img src="http://placehold.it/50" height="50" width="50" alt="Avatar Image"/>
</div>
<div class="small-10 columns">
<%= comment.body %>
</div>
</div>
</div>
Here is how I render that in .../views/posts/show.html.erb
<h4>Leave a comment</h4>
<%= render "comments/form" %>
<h4>Comments</h4>
<%= render #post.comments %>
Edit:Controller .../controllers/comments/comments_controller.rb
class CommentsController < ApplicationController
def create
#post = post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
redirect_to post_path(#post)
end
def destroy
#post = post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body, :post_id)
end
end
Edit: Posts Controller
class postsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:name, :description, :date, :address)
end
end
This will list out the comments, but the first item is always an empty partial, with the placeholder avatar and a delete button. I've checked in rails console to see how many comments a particular post has, just to make sure there wasn't some empty record in the db, but that's not the case. Why am I getting this empty and additional partial that does not match up with a database record?
It is because #post.comments.build in comments/form.html.erb. build() will always create a new empty object, and that comes before render(). Try replacing it with Comment.new so the empty comment won't be associated with the post.
The issue is that the form is above the <%= render #post.comments %> so there is an empty comment when you reach the partial for all the comments, even if there's none in database, put the <%= render "comments/form" %> below to fix this.

User and associated Post

I created an twiiter like app, where friends can post, but i want a include the name of the person who created the post in the list showing all the post.
here is my code
class PostsController < ApplicationController
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
`
Assuming, of course, that the 'user has many posts' association is set, and the user model has a 'username' field, you can do this in your view :
<% #posts.each do |post| %>
<%= post.user.username %>
<% end %>

Resources