I have a list of objects and for each object I have 2 links - "Delete" and "Done". Like this:
1) Buy tomatoes; Delete | Done
2) Wash the car; Delete | Done
But my custom action done don't work. I need your help, how can I make my action and what code should I write in file routes.rb?
Controller:
def done
#task = Task.where(id: params[:id])
#task.done = true
redirect_to "/tasks"
end
Link in view file:
<%= link_to "Done", {:controller => :tasks, :action => :done, :id => task.id}%>
Thanks!
In your controller:
def done
#task = Task.find(params[:id])
#task.done = true
#task.save! # Use the 'bang' method or check the return value
redirect_to tasks_path
end
In routes.rb:
resources :tasks do
get :done, on: :member
end
In your view:
<%= link_to 'Done', done_task_path(task.id) %>
You are assigning the value but not saving the data. So save the data using #task.save
def done
#task = Task.where(id: params[:id])
#task.done = true
#task.save
redirect_to "/tasks"
end
Related
I am trying to set up a simple cart. I want to be able to click on 'add' on a record and then have that item added to the cart with the id of the record/line
<% #documents.each do |document| %>
<td><%= link_to "add", add_to_cart_path(8), :method => :post %></td>
<% end %>
I put the add_to_cart_path(8) as a troubleshooting. I really want that to be add_to_cart(document.id) however, either way, the current doc id parameter is not getting passed to the creation of the new item record.
My route is
post '/add_to_cart/:doc_id' => 'carts#add_to_cart', :as => 'add_to_cart'
The carts controller has
def add_to_cart
$current_doc_id = doc_id
current_cart.add_item(:doc_id)
redirect_to carts_path(current_cart.id)
end
my cart model has
def add_item(document_id)
#line_item = Item.create(:document_id => document_id, :cart_id => $cart_number)
if #line_item.save
# flash[:success] = "item added!"
else
# flash[:fail] = "!"
end
end
When I look at the items table, the record is being created and the cart id is properly populated. However, the document_id field is 'null'.
I know you have the answer, but I wanted to clean up your code a bit...
#config/routes.rb
resources :cart, only: [] do
collection do
post "add/:document_id", to: :create #-> url.com/cart/add/:document_id
delete "remove/:document_id", to: :destroy #-> url.com/cart/remove/:document_id
end
end
#app/controllers/cart_controller.rb
class CartController < ApplicationController
before_action :set_document
def create
current_cart.line_items << #document
redirect_to carts_path current_cart.id
end
def destroy
current_cart.line_items.delete #document
redirect_to carts_path current_cart.id
end
private
def set_document
#document = Document.find params[:document_id]
end
end
This would allow you to use:
<%= link_to "Add to Cart", carts_add_path(#document), method: :post %>
<%= link_to "Remove from Cart", carts_remove_path(#document), method: :delete %>
You have a fundamental antipattern in that you're using request-based logic in your Cart model. Models should only be for data-driven logic; request logic all needs to be kept within your controller:
if #line_item.save
# flash[:success] = "item added!"
else
# flash[:fail] = "!"
end
... needs to be in your controller if you're relying on it to form a response.
We've set up a cart before (using a session model). You may benefit from the code we used. It's fundamentally different to yours in that it keeps the cart in a single session cookie, rather than saving the data in a model:
#config/routes.rb
resources :cart do
collection do
post 'cart/add/:id', to: 'cart#add', as: :cart_add
delete 'cart/remove(/:id(/:all))', to: 'cart#delete', as: :cart_delete
end
end
#app/controllers/cart_controller.rb
class CartController < ApplicationController
include ApplicationHelper
#Index
def index
#items = cart_session.cart_contents
end
#Add
def add
session[:cart] ||={}
products = session[:cart][:products]
#If exists, add new, else create new variable
if (products && products != {})
session[:cart][:products] << params[:id]
else
session[:cart][:products] = Array(params[:id])
end
#Handle the request
respond_to do |format|
format.json { render json: cart_session.build_json }
format.html { redirect_to cart_index_path }
end
end
#Delete
def delete
session[:cart] ||={}
products = session[:cart][:products]
id = params[:id]
all = params[:all]
#Is ID present?
unless id.blank?
unless all.blank?
products.delete(params['id'])
else
products.delete_at(products.index(id) || products.length)
end
else
products.delete
end
#Handle the request
respond_to do |format|
format.json { render json: cart_session.build_json }
format.html { redirect_to cart_index_path }
end
end
end
Then to show the cart:
#app/views/cart/index.html.erb
<% #items.each do |item| %>
<%= item.name %>
<% end %>
I'll delete if inappropriate, I figured it would give you some perspective.
I am implementing a simple voting system and by clicking on a button a +1 is added. For example, if a question has 5 votes, it will just increase. I have written the method already, but I am not sure how to execute it by clicking on a link_to. Do I need to reconfigure my routes?
questions_controller.rb
def self.ping
#question = Question.find(params[:id])
#question.increment!(:amplify)
render_to do |format|
if #question.save
format.html { redirect_to #question }
end
end
end
routes.rb
resources :questions
post '/ping' => 'questions#ping', as: 'ping'
Your routes will need to support an id:
post '/ping/:id' => 'questions#ping', as: 'ping'
Or better yet, if you want it to be scoped within the question:
resources :questions do
post '/ping' => 'questions#ping', as: ping
end
However, I don't think you want a class method ping in your questions_controller. I think you just want an instance method:
def ping
#question = Question.find(params[:id])
#question.increment!(:amplify)
if #question.save
render_to do |format|
format.html { redirect_to #question }
end
end
end
If that doesn't work, what errors do you see in the logs?
Further to CDub's answer, you'll likely benefit from a member route (2.10):
Routes
#config/routes.rb
resources :questions do
member do
post :ping
end
end
This should provide these routes:
http://yourapp.com/questions/:question_id/ping
View
This URL will only be accessible from POST, and would be best accessed using a link_to:
<%= link_to "+1", question_ping_path(question.id), method: :post %>
Controller
You don't need to declare class methods in a controller
#app/controllers/questions_controller.rb
def ping
#question = Question.find(params[:question_id])
#question.increment!(:amplify)
render_to do |format|
format.html { redirect_to #question }
end
end
.increment! saves the record :)
I have Project and ProjectSetting models with following associations:
class Project < ActiveRecord::Base
has_one :project_setting
end
class ProjectSetting < ActiveRecord::Base
belongs_to :project
end
In projects_controller I have:
def show
#project = Project.find(params[:id])
#project_setting = #project.project_setting
end
So I'm using #project_setting form in #project show page and I need to update #project_setting from this page.
In project_settings_controller I have:
def update
#project = Project.find(params[:id]) #problem is here
#project_setting = #project.project_setting
if #project_setting.update_attributes(params[:project_setting])
respond_to do |format|
format.html { redirect_to project_path(#project) }
format.js
end
end
end
But #project variables in these controllers aren't the same:
In projects_controller#show it is Project with ID 26 and in project_settings_controller#update it finds Project with ID 1
So I need to pass #project variable from projects_controller#show to project_settings_controller#update.
Thanks for any help!
In your show.html.erb you can pass the variables back to any controller. For example
<%= link_to "Update project setting",
:controller => "project_settings",
:action => "update",
:project => #project %>
will send the parameter "project" filled with the #project variable.
If you are in a form tag, you can send the variable with a hidden field tag:
<% hidden_field_tag("project", #project) %>
I hope, this helps.
params[:id] in project_settings_controller contained #project_setting.id
If you want to get #project.id from params, you should to write in routes.rb nested path:
resources :projects do
resources :project_settings
end
And then project.id is available in params[:project_id].
Example in rails_guides
I would like to perform this action with the click of a link.
def index
#books = Book.all
end
def update_read_books
#books.each do |book|
book.update_attribute(:read, true)
end
end
How can I update mark all books as read?
Rails has an update_all method. See link.
def mark_as_read
Book.update_all(read: true)
redirect_to books_path
end
Setup up route to give you /books/mark_as_read
resources :books do
get :mark_as_read, on: :collection
end
Then in your view:
= link_to "Mark all as Read", mark_as_read_books_path
If you really want to be Restful, you can make your route a put/patch method. Don't forget to change your link to the method you choose.
If you want this to be an Ajax request, you can add a remote: true to the link:
= link_to "Mark all as Read", mark_as_read_books_path, remote: true
That will make it async. Then you need to handle that response in the controller.
def mark_as_read
Book.update_all(read: true)
respond_to do |format|
format.html { redirect_to books_path }
format.js
end
end
... and add a template inside /views/books/update_all.js.erb and add some jQuery to remove the notification. For example:
$('#notification_count').hide();
First of all define your method outside index method.
def index
#books = Book.all
end
def update_read_books
Book.update_all(read: true)
end
define route:
resources :books do
put :update_read_books, on: :collection
end
Then in your view:
= form_for update_read_books ,:remote => true do |f|
= f.submit "All Read"
Try with this. Hope it will help.
edit: The bug is that the feed_preference is always nil even after the link_to is pressed, so the (if feed_preference == nil) is always true. I still don't know what's causing this.
What this link_to is supposed to do:
When you press the link, it sorts the post index a certain way. One button sorts by trending value, another sorts by time, etc.
for some reason, in the function "make_feed_preference", the #user.feed_preference NEVER changes, even if i hard code it to #user.feed_preference = "foobar"
but it looks like redirect_to 'posts' is working fine.
<%= link_to displayIcon(1), {:action => :make_feed_preference, :id => current_user.id,
:preference => "trending value", :controller => "users"}, :method=>:post %>
in the users controller:
def make_feed_preference
#user = User.find(params[:id])
#user.feed_preference = params[:preference]
#user.save
redirect_to '/posts'
end
in the view for the posts index:
def index
#user = current_user
if #user.feed_preference == nil
#user.feed_preference = "trending value"
end
#posts = Post
unless #user.tag_list == []
#posts = Post.tagged_with(#user.tag_list, :match_all => :true)
end
if #user.feed_preference == "trending value"
#posts = #posts.order('trending_value DESC').page(params[:page]).per(5)
elsif #user.feed_preference == "time"
#posts = #posts.order('created_at DESC').page(params[:page]).per(5)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
end
end
Routes.rb
resources :users do
resources :comments
resources :posts
member do
get :following, :followers
end
collection do
post "tag_with"
post "clear_tag_list_and_preferences"
post "make_feed_preference"
end
end
Whenever I check the values, it's as if clicking the link_to does nothing.
You say it does nothing? The form doesn't even post?
If it's not posting at all... do you have your link_to in a form? If you are using the post method you have to have it in a form unless you are using something like the ujs jQuery libraries which use jQuery / Javascript to help with your 'post' operation.
Using the gem : gem 'jquery-rails'
https://github.com/indirect/jquery-rails
I would also like to see your 'rake routes'