Deleting records using forms in rails 3.2 - ruby-on-rails

I have two models, users and materials. Users can favourite materials. I have set up the relationships and the code for favouriting works fine but I can't seem to get the code for unfavouriting right. I have the following code for unfavouriting:
Materials Controller (in show action where unfavourite form is)
#favourite = Favmat.where(:user_id => current_user.id, :material_id => #material.id)
Note: I use this code to decide which button to show in the view. Assuming a record exists we get this:
View
<%= form_for #favourite, :method => :delete do |f| %>
<%= f.submit "Unfavourite" %>
<% end %>
The problem seems to be here. Nothing I do seems to get me a working route to the destroy action in the favmats controller. I have tried using a form_tag instead but then I get very odd routes that don't work.
Favmats Controller
def destroy
Favmat.find(params[:id]).destroy
respond_to do |format|
format.html { redirect_to #material }
format.js
end
end
Update
I have also tried using link_to instead of a form. The code is as follows:
<%= link_to "Unfavourite", favmat_path, method: "delete" %>
The weird thing is that the html for this takes the favmat id from the material, not the favmat object. I don't know how to get the favmat object id in there. Nothing seems to work.

Try passing #favourite object instead of favmat_path to link_to:
<%= link_to "Unfavourite", #favourite, method: :delete %>

Related

How to replace a div tag in my view using Ajax

I want to replace a div tag on my Images index page using Ajax. Right now, I have the following:
_sub.html.erb
<% #group.images.each do |image| %>
<%= image_tag image.pic.url(:medium) %>
<%= button_to '+1', image_upvote_path(image), remote: true, method: :post %>
<% end %>
index.html.erb
<div id="next_group">
<%= render 'sub' %>
</div>
upvote.js.erb
$("#next_group").empty();
$("#next_group").append("<%= j render 'sub' %>");
In my images_controller
def index
#group = Group.offset(rand(Group.count)).first
end
def upvote
#image = Image.find(params[:image_id])
#image.votes.create
respond_to do |format|
format.html { redirect_to groups_path }
format.js
end
end
And in my routes, I have
image_upvote POST /images/:image_id/upvote(.:format) images#upvote
My understanding of what is going on:
On my index page I have a div container that renders the sub partial that I want users to see. Inside the sub partial, I have a button_to helper that has the remote: true attribute(?) included as well as the path/action that clicking that button will initiate. The action is the images#upvote. So in the images controller, I define what I want to happen when the button is clicked (an upvote is created), but I also say that I want it to respond with Ajax, which happens because I've declared remote: true.
Here's where I start getting a little confused. Since Ajax is being used, does rails automatically look for the upvote.js.erb file since it's the upvote action that is occurring?
My problem right now is that the vote is being created just fine, but I don't think the javascript in upvote.js.erb is being executed. The page will stay on the current #group that is being displayed, without rendering a new _sub partial. So I guess I'm not sure if there is a problem with the javascript, or maybe something with the way I have the controller, views, and routes set up.
maybe button not belongs to any form, try using link_to or add remote options to the path

Ruby on Rails - redirect_to

I'm having some trouble understanding the redirect_to statement.
I have a model "Book" (with an boolean attribute "read")and a controller "books". Now I created a second controller "Admins" having to methods: index and change.
The index view just renders a list off all Books with a link to the change method:
<% #Books.each do |d| %>
<%= d.title %><br>
<% if d.read==true %>
<%= link_to "mark unread", change_path(:id=>d.id)%>
<% else %>
<%= link_to "mark read", change_path(:id=>d.id)%>
<%end %>
Now the change method just changes the "read" attribute:
#book=Book.find(params[:id])
if #book.read==true
#book.update_attributes(:read => false)
else
#book.update_attributes(:read => true)
end
redirect_to action: "index"
The Problem is: rails tries to redirect me to the show action using the :id as a parameter...(perhaps because the change_url is /admins/change?id=3)
But I just want to be directed back to the index view "/admins"
is there a way? it seems like rails always tries to redirect to the view action if there is an id as a parameter
Thanks alot
PS: the routes.rb contains resources:admins and resources:books
Use this
redirect_to :controller => 'admins', :action => 'index'
Or
redirect_to admins_url
The above two will direct you to the index page of AdminsController. There is no way that Rails would route it to show action UNLESS you are redirecting to show action from the index action of AdminsController. Since, you did not share index action code of AdminsController, I would recommend you to check there.
If you want a clear explanation of redirect_to ... checkout
https://gist.github.com/jcasimir/1210155
I had a kind of similar issue some days ago. I would suggest to do this within the form where you list the books and the mark/unmark checkboxes.
<%= form_for #book,:url => book_index_path do |f| %>
This worked fine for me, when I set up a site where you create data and the user is immediately redirected to the same page (incl. success/error message).. to do a kind of
human batch-processing.

How do I use another value of a key in a hash if the first one doesn't exist, like some type of fallback in ruby/rails?

Basically I have a follow button and when click the page refreshes and I show an unfollow button in place. Below is the code I use to render the particular form needed:
follow_forms partial:
<% unless current_user?(#user) %>
<% if current_user.following?(#user) %>
<%= render 'relationships/partials/unfollow' %>
<% else %>
<%= render 'relationships/partials/follow' %>
<% end %>
<% end %>
Any I changed the form to an ajax form because I don't want the page refresh and on success of the form submission I'd like to replace the follow button/form with an unfollow button/form. This isn't straight forward because only 1 form shows at a time so I can't use my jquery selector to find this form anyway.
What I decided to do was create a new action that renders the follow_form partial this way the appropriate form will be available for me to manipulate with my jquery selector.
The new action:
class RelationshipsController < ApplicationController
def get_follow_form
respond_to do |format|
format.html { render :partial => 'relationships/partials/follow_form_ajax' }
end
end
end
The problem now is that I don't have access to the #user instance variable. That doesn't matter to much because I can get the user who was just followed via the jquery success data then pass that as data in the new ajax call to get_follow_form_url and then pass that info into the partial as a local variable.
I still have an issue with the #user instance variable not being available. Which brings me to my question.
How can I make another value be used if the instance variable isn't nil/doesn't exist?
The form for following:
<%= form_for current_user.relationships.build(:followed_id => #user.id), :remote => true do |f| %>
<%= f.hidden_field :followed_id %>
<%= f.submit "Follow", :class => 'followButton' %>
<% end %>
Can I do something like this
:followed_id => #user.id <-if this doesn't exist use this-> user.id
There are other ways around this like creating new partials that are only used for this whole situation or creating some messy if statements but I feel like creating duplicate forms should be my very very very last option.
I look forward to you solutions thanks
Kind regards
There's a very simple way to do this, assuming you have your 'fallback' ID:
:followed_id => #user.present? ? #user.id : fallback_id
Use something like the andand gem or just try and a logic expression:
:followed_id => #user.andand.id || user.id
Even without that you can use identical logic, and certainly don't need multiple partials:
:followed_id => (#user && #user.id) || user.id
But as Frederick says, if you have a replacement value for the object already, couldn't you just set it?

best practice for using a date selector in an overview/index

I am new to rails and try to realise a overview of a list of meetings created using the index method in the meeting controller. The page has also a select with all years, so that you can select a specific year to see only the meetings of the selected year. I realized it adding a form on the page:
index.html.erb:
<h1>Protokolle</h1>
<%= form_tag 'meetings', :method => :get do %>
<%= select_tag :selected_year, options_for_select(available_years, #year), {onchange: 'this.form.submit();'} %>
<% end %>
<%= link_to image_tag('new'), new_meeting_path %>
...
Using put as the action method of the form, does not work, but get seems to be ugly.
How can this be done better?
meetings_controller:
class MeetingsController < ApplicationController
def index
#year = selected_year(params[:selected_year])
#meetings = Meeting.where(:held_on => ("01.01.#{#year}".to_date)..("31.12.#{#year}".to_date)).order('held_on desc').all
respond_to do |format|
format.html # index.html.erb
end
end
...
Thanks for your tips ...
There's no problem using GET in a form for a get-only action. PUT doesn't work, because of RESTful routes - the POST version would activate the 'meetings' route will call 'create' for a new meeting, PUT is simply denied by the router as not existing.

Ruby on Rails -Problem using subdirectories

I have tried to set up a separate section of my app using a subdirectory called controlpanel to manage various parts of the site.
I've set up the namespace in my routes.rb
map.namespace :controlpanel do |submap|
submap.resources :pages
# other controllers
end
And placed the controller and views into the relevant subdirectories.
Controlpanel::PagesController
def new
#page = Page.new
end
def create
if #page = Page.create_with_author(current_user, params[:page])
flash[:notice] = 'Page was successfully created.'
redirect_to ([:controlpanel, #page])
else
render :action => 'new'
end
end
Using this mixed in class method
def create_with_author(author, params)
created = new(params)
created.author = author
if created.save
created
end
end
And the view (controlpanel/pages/new.html.erb renders a partial called _form
<%= render :partial => 'form' %>
Which is as follows:
<% semantic_form_for([:controlpanel, #page]) do |form| %>
<% form.inputs do %>
<%= form.input :title %>
<%= form.input :body %>
<% end %>
<%= form.buttons %>
<% end %>
If I fill in the form correctly, it works as expected, redirecting me to the new page, however, if I leave fields blank, violating the validation constraints, I get the following error:
RuntimeError in Controlpanel/pages#create
Showing app/views/controlpanel/pages/_form.html.erb where line #1 raised:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Can anyone see what is going wrong?
I'm using the formtastic plugin to create the form, but it still happens if I use a regular form.
Any advice greatly appreciated.
Thanks.
Given that the create action is called and new is rendered, Page.create must evaluate to nil.
You probably want to pass params[:page] to create.

Resources