Multi update boolean state with checkboxes (Rails 3) - ruby-on-rails-3

well this problem I'm sure it isn't difficult at all but being new to rails I'm kinda lost.
After watching Railscasts Episode #52, I went on to make my own publish/unpublish list of slides.
So this is the form view
= form_tag publish_admin_category_slides_path(#cat4), :method => "put" do
#pricing
%table#plans
%thead
%tr
%th Image
%th Published
%tbody
- #image.each do |im|
%tr.odd
%td
= image_tag im.avatar.url(:thumb)
= link_to "Delete", admin_category_slide_path(#cat4,im), :method => "delete"
%span is
%th
= check_box_tag "slide_published[]", im.published ,im.published
With controller action #publish
def publish
Slide.update_all(:published => params[:slide_published])
redirect_to :action => "index"
end
What would be the correct way to write something like this?
A list with checkboxes that changes boolean state of an attribute and multi updates?

Some xp l8r I was able to find something like this.
I post it in case someone has a similar problem
def publish
#cat = Category.find(params[:category_id])
if params[:slide_published]
checked_slides = Slide.find(params[:slide_published])
end
unless checked_slides.blank?
#cat.slides.all.each do |slide|
if checked_slides.include?(slide)
slide.update_attribute :published, true unless slide.published?
else
slide.update_attribute :published, false unless !slide.published?
end
end
end
if checked_slides.blank?
#cat.slides.all.each do |slide|
slide.update_attribute :published, false unless !slide.published?
end
end

Related

Rails: form_for in application wide footer

I started learning Rails for about a month now and I am working on a fairly simple project to improve my skills. It's a blog where editors can add articles and users can subscribe to a newsletter by adding their email. The homepage is an index view and their is a footer that shows up across all pages.
Here is my problem: I would like to include the form_for the newsletter on the footer that exists inside the application layout. That form has a specific model: Subscriber, which stores users emails.
What I've done so far is include the following on the Articles controller:
def index
#articles = Article.order(created_at: :desc).all
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.new(subscriber_params)
if #subscriber.save
redirect_to '/home'
else
render 'new'
end
end
def subscriber_params
params.require(:subscriber).permit(:email)
end
In application.html.erb :
<%= form_for(#subscriber) do |f| %>
<%= f.email_field :email, :placeholder => "email address" %>
<%= f.submit 'Sign up', :id => "signup" %>
<% end %>
The form is displayed correctly on the index page only and it doesn't save to the database (without error).
I have tried using a before filter on the application controller as well as rendering a partial without any success.
Edit
Subscribers controller code:
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.new(subscriber_params)
if #subscriber.save
redirect_to '/home'
else
render 'new'
end
end
private
def subscriber_params
params.require(:subscriber).permit(:email)
end
Application controller:
before_action :create_new_subscriber
def create_new_subscriber
#subscriber = Subscriber.new
end

Unkown Action - The action could not be found for Controller

I've read a few similar questions/answers but cannot find any answers to my bug.
I have a form for entering hours for a job and one for editing an hours record. Both the add and edit share a partial as per Rails guidelines. My add (new) form works fine. When submitting the edit form, I get the error/bug:
Unknown Action
The action '11' could not be found for HoursController
I get no other output on this screen.
The url shown for these screens are:
http://localhost:3000/hours/11/edit
after submit:
http://localhost:3000/hours/11
The form tag for my edit form is:
<%= form_for(:hour, :url => {:action => 'update', :id => #hour.id}) do |f| %>
This should go to the 'hours' controller, to the 'update' action. Maybe there is something else wrong with my controller, but the add/new form works fine... confusing...
My Controller:
class HoursController < ApplicationController
before_filter :confirm_logged_in
def index
end
def list
if !params[:job_id].nil?
#hours = Hour.where(["job_id = ?",params[:job_id]]).date_sorted
else
#hours = Hour.date_sorted
end
end
def show
#hour = Hour.find(params[:id])
end
def new
#hour = Hour.new
end
def create
#hour = Hour.new(params[:hours])
if #hour.save
job = Job.find(params[:hours][:job_id])
flash[:notice] = "You have just entered hours for #{job.name}"
redirect_to(:action => "list", :job_id => params[:hours][:job_id])
else
flash[:notice] = "There were one or more problems with your form. Please try again!"
render('new')
end
end
def edit
#hour = Hour.find(params[:id])
end
def update
#hour=Hour.find(params[:id])
if #hour.update_attributes(params[:hour])
flash[:notice] = "You have just updated an Hours entry"
redirect_to(:action => "list", :job_id => params[:hours][:job_id])
else
render("edit")
end
end
def delete
#hour = Hour.find(id)
end
def destroy
Hour.find(params[:id]).destroy
flash[:notice] = "Hours Deleted Successfully!"
redirect_to(:action => 'list')
end
def search
if params[:job][:id]
#job = Job.find(params[:job][:id])
redirect_to(:action => "list", :job_id => #job.id)
end
end
end
My Routes file for the Hours section
resources :hours do
collection do
get :list
get :delete
end
end
Which gives me:
list_hours GET /hours/list(.:format) hours#list
delete_hours GET /hours/delete(.:format) hours#delete
hours GET /hours(.:format) hours#index
POST /hours(.:format) hours#create
new_hour GET /hours/new(.:format) hours#new
edit_hour GET /hours/:id/edit(.:format) hours#edit
hour GET /hours/:id(.:format) hours#show
PUT /hours/:id(.:format) hours#update
DELETE /hours/:id(.:format) hours#destroy
Any ideas in how to figure this out would be greatly appreciated.
--jc
Try like this
<% form_for #hours do |f| %>
or else
<% form_for :hours, :url =>
url_for(:action => "update", :id => #hours) do |f| %>
My situation was slightly different because I had a custom route, but it may help someone else (or future me).
I kept getting that error until I added the method: :post to the form params.
routes:
resources :hours do
member do
post :fix
end
end
html.erb
form_for #hour, url: fix_hour_path(#hour), method: :post do
...
end

Ajax deleted items are shown after refreshing the page

Hi i am new in rails and i am using rails 3.My que is i want to delete an image from the list using ajax. When i click on delete button, image is still visible on the index page, however actually it gets deleted but user can see changes after refreshing the web page. I want it visible on the same page as the ajax is used for. Any one please help. Thank you...
My code for controller is:
def destroy
logger.info params[:event].inspect
#event = Event.find(params[:id])
#event.destroy
#redirect_to events_url
respond_to do |format|
format.html { redirect_to #event, :notice => 'Event deleted' }
format.js
end
end
My code for view is:
**app/view/events/index.html.haml**
- #events.each do |event|
%ol.hoverbox
%li.all{:id =>"event_#{event.id}"}
= link_to image_tag(event.photo.url), event_path(event)
.abc
= event.name
%br/
.bca
= event.start_date
|
= event.start_time
|
= link_to " ".html_safe, event_path(event), :remote => true, :method => :delete, :class => "del-16", :confirm=>"Are u sure?", :title => "Delete", :style => "text-decoration:none;"
code for js is:
*destroy.js.erb*
$("#event_#{event.id}").fadeOut().remove();
I think you need to look at here
write something like this
$("#event_#{event.id}").reset(); in your destroy.js.erb file.
I hope this would help you.
Thanks.

Changing boolean value in Rails 3 app yields ArgumentError

In my Rails 3.0.5 app I have columns on my Profile model for privacy. In each User's settings, I want the user to be able to change their settings so they can determine which parts of their profile are shown. In my migration I added four boolean attributes for this. However when I try to update the value (switch between true/false) I get an ArgumentError:
ArgumentError (wrong number of arguments (1 for 2)):
app/controllers/profiles_controller.rb:162:in `edit_settings'
An example of the params passed:
{"utf8"=>"✓",
"authenticity_token"=>"0uySkgRNsIIQSX6PtXl3e0e+MXCTo4yuoU/QjuBxENw=",
"show_hometown"=>"1"}
Here is the boolean in my migration:
t.boolean :show_hometown, :default => true
Here is the controller action edit_settings I'm using to update. There are four if statements to update_attribute, but for length I'm only including two:
def edit_settings
#profile = current_user.profile
if #profile.update_attribute(:show_hometown)
redirect_to settings_path, :notice => 'Updated user information successfully.'
else
redirect_to settings_path, :notice => 'Oops, something went wrong. Please try again.'
end
...
if #profile.update_attribute(:show_current_location)
redirect_to settings_path, :notice => 'Updated user information successfully.'
else
redirect_to settings_path, :notice => 'Oops, something went wrong. Please try again.'
end
end
And the form for updating :show_hometown:
<%= form_tag({:action => "edit_settings", :controller => "profiles"}, :html => {:multipart => true }) do %>
<%= check_box_tag :show_hometown %>
<%= #user.profile.hometown %>
<% end %>
FOLLOW-UP:
If I use validations on :show_hometown and insert the following into my controller I can see the value toggle:
def edit_settings
#profile = current_user.profile
if #profile.show_hometown == true
if #profile.update_attributes(:show_hometown => false)
redirect_to settings_path
else
redirect_to settings_path, :notice => 'Oops, something went wrong. Please try again.'
end
elsif #profile.show_hometown == false
if #profile.update_attributes(:show_hometown => true)
redirect_to settings_path
else
redirect_to settings_path, :notice => 'Oops, something went wrong. Please try again.'
end
end
end
However, since I have four booleans where I'll apply the same code is there a way to handle each update in one controller action? Or do I need to create a separate action for each boolean attribute I want to update?
You have to tell update_attribute the column and the value:
#profile.update_attribute(:show_hometown, params[:show_hometown])
This means set the value of column show_hometown to the value in params[:show_hometown].
Note that with update_attribute validations are skipped. If you want validations to run, you have to use update_attributes:
#profile.update_attributes(:show_hometown => params[:show_hometown])
To answer your follow-up: with update_attributes you can update several columns in one call:
#profile.update_attributes({:show_hometown => !#profile.show_hometown,
:show_birthdate => !#profile.show_birthdate})
There is also a toggle method, but using that would result in 4 database calls instead of 1. It can be written in one line:
%w{show_hometown show_birthdate}.each { |attr| #profile.toggle(attr) }

Rails 3 rendering form with an array of nested attributes after failing validation

I have question model which has many options.
In my question controller new action I create five options ready for my user
def new
#question = Question.new
5.times.with_index do |index|
#question.options.build(:order => index)
end
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #question }
end
end
In the view I loop through all options
- form_for(#question) do |f|
.field
= f.label :title, t("question.title")
= show_errors_for(#question, :title)
= f.text_field :title
- #question.options.each do |option|
- f.fields_for :options, option do |o|
.field
= o.label :option, t("question.option_no", { :index => option.order })
= o.text_field :option
= o.hidden_field :order, :value => option.order
.actions
= f.submit t("add_question.create")
My question model looks like this
class Question < ActiveRecord::Base
attr_accessible :title, :options_attributes
belongs_to :user
has_many :options
accepts_nested_attributes_for :options, :reject_if => proc { |attributes| attributes['option'].blank? }
validates :title, :length => { :maximum => 100 }, :presence => true
validate :min_no_of_options
def min_no_of_options
if self.options.size < 3
errors.add_to_base "Must have at least three options"
end
end
end
And my question controller create action
def create
if current_user
#question = current_user.questions.build(params[:question])
else
#question = Question.new(params[:question])
end
if #question.save
redirect_to(#question, :success => t('question.flash_success'))
else
flash.now[:error] = t("question.flash_error")
render :action => "new"
end
end
Now, when I enter only two options in the form and hit the create button the validation prevents the model from being saved. Which is good. But when the create action renders the new action again, only the option fields that I filled are showing up. The three option fields which were left blank have disappeared.
If I replace the "#question.save" in my create action with "false", the behavior is the same. So this suggests that something in the way I create the #question variable in the create action is responsible for throwing away my empty options.
But if I instead remove the :reject_if from my question model the empty options are showing up after a failing question save as expected. (I have a presence validation for the option attribute in my option model) So this tells me that there is nothing wrong in the way I create the #question variable in the create action. It is not throwing away the empty options. So where they are kicked out?
There was one pretty similar question, but the answer in there is not something I would like to do. Though it might be something I have to do.
rails fields_for does not render after validation error on nested form
EDIT
After some more study with rails console I noticed that it truly is the creation of #question variable where the empty options get thrown away. This happens because I have the reject_if defined in the question model. After commenting the reject_if out from the model the empty options were added into the #question variable.
So I guess I need to remove the reject_if and use after_save callback to destroy empty options from the database. This way I will have the empty options going along with the question until the question is saved.
I'm answering my own question because I got the issue solved.
Blank "options" were removed from the "question" because of reject_if in the "question" model. The reject_if statement was applied when the code below was executed, and therefore blank "options" were removed.
#question = current_user.questions.build(params[:question])
I replaced the reject_if with an after_save callback which removes the options which were left blank.