Rails 4 - update_attributes not updating - ruby-on-rails-4

I have the following form:
<%= form_for #user, :html => {:class => 'edit-form' }, :url => {:action => 'add_group', :id => #user.id }, :remote => true do |f| %>
<%= f.select :group_ids, Group.all.collect {|x| [x.name, x.id]}, {}, :class => 'multiselect', :multiple => true %>
<button type="submit" id="submit_it" class="btn btn-primary">Submit</button>
<% end %>
And in my controller:
def add_group
#user = User.find(params[:id])
unless #user.update_attributes(option_params)
respond_to do |format|
format.html
format.js
end
end
end
def option_params
params.require(:user).permit!
end
And thus, when the form is submitted, I do get a response with my "update.js.erb" file, and the following shows up in the console:
Started PATCH "/user_management/add_group?id=41" for 123.45.67.89 at 2014-07-07 22:58:38 +0000
Processing by UserController#update as JS
Parameters: {"utf8"=>"✓", "user"=>{"group_ids"=>["", "3", "4"]}, "multiselect"=>"4", "id"=>"add_group"}
Rendered user/update.js.erb (0.1ms)
Completed 200 OK in 13ms (Views: 11.9ms | ActiveRecord: 0.0ms)
But, nothing actually gets updated in the database.
There are no validations in my model that would be causing this not to update.
My model relationships are such:
class User < ActiveRecord::Base
has_many :group_assignments
has_many :groups, through: :group_assignments
end
class Group < ActiveRecord::Base
has_many :group_assignments
has_many :users, through: :group_assignments
end
class GroupAssignment < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
Any ideas on why this would not be updating?
Update
I thought it might be because the form is loaded via AJAX and there is no CSRF tags. So I added <%= hidden_field_tag :authenticity_token, form_authenticity_token %> to the form. Now, the authenticity token is in the params.

And thus, when the form is submitted, I do get a response with my "update.js.erb" file, and the following shows up in the console... But, nothing actually gets updated in the database.
Well, yes. Your code says, "unless the attributes are updated successfully, respond to html and js." And since the attributes aren't updated, it renders the template that corresponds to the request format. (For this reason, I try to use if as much as possible, instead of unless. It makes the code easier to read and understand.)
One method you can use to get more information is to change the method to update_attributes!. This will make it so that, instead of simply returning false, the method will raise an exception if the record is invalid for some reason.
As a side note, you should avoid using permit!. The entire point of strong parameters is that you make conscious decisions about which attributes to allow.

Related

Kaminari paginate at different controller mixing with devise (check answer)

I have 2 non nested models, User and Record. The goal is to paginate the #user.records called #records at users/show
Here is the Record part:
at app/models/record.rb
class Record < ActiveRecord::Base
default_scope lambda { order('records.created_at DESC') }
paginates_per 48
end
I am using Kaminari at records/index and works great. Problem is to use it at users/show
Here the app/controllers/users_controller.rb
def show
#user = User.find(params[:id])
#records = #user.records.page params([:page])
# Not working alternative:
# #records = #user.records.page(params[:page]).per(48)
end
Here is the view that triggers the display, is the listing rendered inside users/show...
<% #records.each do |record| %>
<%= link_to (image_tag record.thumbnail.url(:list)), record %>
<%= link_to record.name, record %>
<% end %>
<%= paginate #records %>
Errors are very interesting. As it is, error is:
No route matches {:action=>"show", :controller=>"users", :controllers=>{"registrations"=>:registrations}, :id=>"1", :page=>nil}
Meaning paginate #records is building a request to Active Record that hopes to find an action I do not have in that controller (I am using devise). So at Kaminari instructions says is possible to pass the params, like this:
<%= paginate #records, :params => { :controller => 'foo', :action => 'bar' }, :remote => true %>
Then the error becomes like this:
No route matches {:action=>"remote_records_pagination", :controller=>"records", :controllers=>{"registrations"=>:registrations}, :id=>"1", :page=>nil}
I have a remote_recors_pagination defined at records_controller, renders records_paginate_remotely.js, but the pagination method does not find it. Why it keeps showing :controllers registrations?
Finally, to change the view like this:
<%= paginate #user.records %>
<% #user.records.each do |record| %>
<%= link_to (image_tag record.thumbnail.url(:list)), record %>
<%= link_to record.name, record %>
<% end %>
<% end %>
Produces an undefined method error.
Should not the example be working with or without js file? Any help?
Thanks.
I found a solution. I am posting an answer because the problem was on routes and the mix with devise, common combo that more people may find.
So, routes was like this:
devise_for :users
resources :users, only: :show, , :controllers => { :registrations => :registrations } do
member do
get :following, :followers
end
end
To change it to this:
devise_for :users, :controllers => { :registrations => :registrations }
resources :users, only: :show do
member do
get :following, :followers
end
end
allows the paginate command interact with Active Record normally. Devise first test seems ok.

Whats the best way to create a self-referential association in Rails 4?

In my project I am dealing with objects called Workflows. Every Workflow can have many subflows (Workflows that it calls). At the same time every workflow (Including ones with sub flows) may also act as a Superflow that is calling the sub-flows and may have many Superflows that call it as a sub flow.
I am currently trying to do this by using a join table through a model called FlowRelation.
I have followed every tutorial I can find and read every article I can find and I still can't get this working.
Workflow Model:
class Workflow < ActiveRecord::Base
belongs_to :superflow, :class_name => 'Workflow'
has_many :subflows, :class_name => 'Workflow', :foreign_key => 'subflow_id'
end
FlowRelation Model:
class FlowRelation < ActiveRecord::Base
belongs_to :workflow
belongs_to :flow, :class_name => "Workflow"
end
Inside my workflows edit.html.erb (Using SimpleForm)
<%= simple_form_for #workflow, :html => { :class => 'form-horizontal', :multipart => true } do |f| %>
<%= f.input :workflow_id %>
<%= error_span(#workflow[:workflow_id]) %>
<%= f.association :subflows, :include_blank => t('.select_workflow') %>
<%= error_span(#workflow[:subflow_id]) %>
<%= f.association :superflow, :include_blank => t('.select_workflow') %>
<%= error_span(#workflow[:superflow_id]) %>
And my Workflow Controller is pretty straightforward
def new
#workflow = Workflow.new
end
def edit
#workflow = Workflow.find(params[:id])
#workflow.save
end
Currently, when I attempt to save new sub_flows to an existing or new Workflow, nothing ever gets saved. Nothing shows up in the database, and I see no error.
I also have a FlowRelationsController
class FlowRelationsController < ApplicationController
before_action :set_flow_relation, only: [:show, :edit, :update, :destroy]
def create
#flow_relation = current_workflow.flow_relations.build(:flow_id => params[:flow_id])
if #flow_relation.save
flash[:notice] = "Added flow."
redirect_to root_url
else
flash[:error] = "Unable to add flow."
redirect_to root_url
end
end
If I attempt to create an add sub_flow button to my workflow index with
<%= link_to "Add Subflow", flow_relations_path(:flow_id => workflow), :method => :post %>
My flow_relations table remains empty as well. and I get the following error:
undefined local variable or method `current_workflow' for #
<FlowRelationsController:0x007f70154921e0>
I know its a bunch of pieces, but I'm completely stuck, been hitting my head against a wall on this one for days. Anyone see something I'm missing here? I've been trying to implement something similar to what was described on RailsCasts here with no success: http://railscasts.com/episodes/163-self-referential-association?view=asciicast
Please HELP!
Thanks
Without digging into any of the other self-referential model stuff you're doing here, the error you see is a controller error. It doesn't know about 'current_workflow'. My guess is that in your 'set_flow_relation' before callback, you are setting #current_workflow. I cannot be sure without seeing the rest of your controller code.
Once that is fixed, please post any follow up problems you have.
I was misunderstanding a couple different things. I thought I'd answer my own question to help bring clarity to any others who may be in the same boat.
1st major issue I had above was in the FlowRelationsController. I was using an object called current_workflow which didnt exist. This happened due to following the only video i could find online about this topic at: http://railscasts.com/episodes/163-self-referential-association. This is a create resource, but is not entirely the same as what I was trying to accomplish. The current_workflow object wasnt being created in my case because I was starting from an index and not a workflow details section of my application
Now, as to how to accomplish my original goal. Here is what I ended up with:
Workflow Model
has_many :flow_relations
has_many :subflows, :through => :flow_relations
FlowRelation Model
self.primary_key = :workflow_id
belongs_to :workflow
belongs_to :subflow, :class_name => 'Workflow'
Inside of my simpleForm used for creation and editing of workflows. (This was a pretty key piece to understand. - doing the association to subflows with a collection of all workflow objects.
<%= f.association :subflows, collection: Workflow.all, prompt: "Select Subflows" %>
<%= error_span(#workflow[:subflow_id]) %>
The Workflow controller stayed mostly the same with one key difference due to Rails 4. - I had to change the workflow_params to permit!. I did this on both the Worfklow Controller and the FlowRelations controller. Not sure I understand still how this should be configured for better security, but in this particular application, security is not an issue as its to be run internally.
def new
#workflow = Workflow.new
end
def edit
#workflow = Workflow.find(params[:id])
#workflow.save
end
def workflow_params
#params.require(:workflow).permit(:workflow_id, :flow_relations, :re_workflow_id, :name, :description, :superflow_id, :client_id, :variable_id, :required_variable_id, :flow_file)
params.require(:workflow).permit!
end
I removed the add subflow button, since now it could be done through the standard create or edit actions
Its a bunch of stuff, but basically, the end result is I now have a Workflow object that can contain mnay subflows all of which can be a member of many Workflows, all within a single Workflow class and a FlowRelations class for handeling the join.

Rails comments gem Acts_as_commentable on pins

I have a rails app where users can upload pins, I want to use the [acts_as_commentable_gem][1] to allow users to comment pins, here is my config:
app/models/pin.rb
class Pin < ActiveRecord::Base
acts_as_commentable
end
app/controlers/pins_controller.rb
def show
#pin.find params[:id]
#comment = #pin.comments.new
end
app/views/pins/show.html.erb
<%= form_tag "/pins/add_new_comment" do %>
<%= hidden_field_tag "id", post.id %>
<%= text_area_tag "comment[comment]" %>
<%= submit_tag "Pin Comment" %>
<% end %>
app/models/comment.rb
class Comment < ActiveRecord::Base
include ActsAsCommentable::Comment
belongs_to :commentable, :polymorphic => true
default_scope -> { order('created_at ASC') }
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_voteable
# NOTE: Comments belong to a user
belongs_to :user
end
app/controllers/pin_controller.rb
def add_new_comment
pin = Pin.find(params[:id])
pin.comments << Pin.new(params[:comment])
redirect_to :action => :show, :id => pin
end
finally in my config/routes
get "/pins/add_new_comment" => "pins#add_new_comment", :as => "add_new_comment_to_pins", :via => [:pin]
But I run to a routing error:
undefined local variable or method `acts_as_commentable' for PinsController:Class
I am really not sure where this error come from, any ideas?
I am not really sure but you route shouldn't be like
get "/pins/:id/add_new_comment" => "pins#add_new_comment", :as => "add_new_comment_to_pins"

Nested attributes using paperclip rails 4

I am new to rails and I am trying to work with nested attributes.
The main idea is to have a a deal(offer) model, a deal will have multiple deal_photos from paperclip.
I have already watched Ryan's Railscast for nested forms and read many articles with many tips regarding problems on the same issue but still it doesn't work for me.
Here is my Implementation:
class Deal < ActiveRecord::Base
belongs_to :user
has_many :deal_photos, dependent: :destroy
accepts_nested_attributes_for :deal_photos
end
class DealPhoto < ActiveRecord::Base
belongs_to :deal
has_attached_file :photo, :styles => { :large => "600x170", :medium => "250x250!", :thumb => "100x100>" }, :default_url => lambda { |photo| photo.instance.set_default_url}
def set_default_url
ActionController::Base.helpers.asset_path('missing.png')
end
end
In my deals controller:
class DealsController < ApplicationController
def new_deal
#deal=Deal.new()
#user= User.find(params[:id])
3.times { #deal.deal_photos.build }
end
def create
#deal = Deal.new(deal_param)
#user= User.find(params[:user_id])
if #deal.save
#user.deals << #deal
flash[:notice]="Thank you"
end
end
def edit
#deal=Deal.find(params[:deal_id])
3.times { #deal.deal_photos.build }
end
def update
#deal=Deal.find(params[:id])
if #deal.update_attributes(deal_params)
flash[:notice]="Deal updated successfully"
end
end
private
def deal_params
params.require(:deal).permit(:title, :description, :contact_num, :user_id, :deal_photos_attributes => [ :id, :caption, :photo, :deal_id])
end
Finally in my form for a new deal:
<%= form_for(:deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
<label>Title<b style="color:red;">*</b>
<%= f.text_field(:title, :placeholder=>"") %>
</label>
------------more fields---------------------
<%= f.fields_for :deal_photos do |builder| %>
<div>
<%= builder.label :caption, "Image Caption" %>
<%= builder.text_field :caption %>
<%= builder.label :photo, "Image File" %>
<%= builder.file_field :photo %>
</div>
<%end%>
<%= button_tag("Create", :class=> "secondary button", :button_type => "submit") %>
(I have migrated the db for deals_photo to accept paperclip)
The above, creates a form with all fields but instead of 3 inputs for file upload shows only one. It creates 3 empty associations #deal.deal_photos but even if I choose one image to upload from the form it doesn't save it.
If you have any useful advices or another similar question please help!
What's in your deal_param method?
Do you permit deal_photos' attributes in it?
If no then do something like
def deal_params
params.require(:deal).permit(deal_attr1, deal_attr2,...., deal_photos_attributes: [:deal_photo_attr1, ...])
end
Also, do you get a deal_id in your deal_photos in view?
Finally, I was able to solve the problem in the new_deal.html.erb when I replaced the:
<%= form_for(:deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
with
<%= form_for(#deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
What is changed is that the second line is for the specific new deal instance. Maybe the reason that the first was not working is that the deal_photos didn't get the deal_id, as Alexphys said. But still I haven't figure out the exact reason.

undefined method `permit' for "Submit Now! ":String. Where am I going wrong?

I've been trying like crazy to work through this permit error using some of the other StackOverflow postings, but can't seem to get past it. I've got a projects model & controller & a versions model & controller. Projects/##/versions/new is a form page to create a new version of project id ##. But when I click the submit button to create the version...it throws the following error in the VersionsController:
undefined method `permit' for "Submit Now! ":String
Extracted source (around line #36):
34
35
36
37
38
def version_params
params.require(:version).permit(:title)
end
end
Any and all help would be greatly appreciated...I've been trying to fix this for too long now. My Code is as follows:
ROUTES.RB
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :projects, only: [:create, :new, :show, :edit, :update, :destroy]
resources :projects do
resources :versions
end
# get "static_pages/home"
# get "static_pages/help"
# get "static_pages/about"
#The original routes above map to...
root 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
PROJECTS MODEL:
class Project < ActiveRecord::Base
has_many :users
has_many :versions, dependent: :destroy
validates :title, presence: true, length: { maximum: 100 }
validates :background, presence: true
validates :user_id, presence: true
default_scope -> { order('created_at DESC') }
end
VERSIONS MODEL:
class Version < ActiveRecord::Base
belongs_to :project
validates :title, presence: true, length: { maximum: 140 }
default_scope -> { order('created_at DESC') }
end
VERSIONS CONTROLLER:
class VersionsController < ApplicationController
def new
#version = Version.new
end
def show
#project = Project.find(params[:project_id])
#version = Version.find(params[:id])
end
def index
#versions = Version.paginate(page: params[:page])
end
def create
#project = Project.find(params[:project_id])
#version = #project.versions.create(version_params)
if #version.save
flash[:success] = "You've successfully added a version to this branch..."
redirect_to project_path(#project)
else
render 'new'
end
end
def edit
end
def update
end
def destroy
end
private
def version_params
params.require(:version).permit(:title)
end
end
NEW.HTML.ERB (new version form):
<% provide(:title, 'New Version') %>
<h1>Add a version to this project</h1>
<div class="row-fluid">
<div class="col-md-5 no-pad offset3">
<%= bootstrap_form_for #version, :url => project_versions_path do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :title %>
<br clear="all">
<%= f.submit "Submit Now! ", class: "btn btn-lg btn-primary" %>
<% end %>
</div>
</div>
PARAMS:
{"utf8"=>"✓",
"authenticity_token"=>"######AAAA",
"submit"=>"Submit Now! ",
"project_id"=>"51"}
Processing by VersionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"################=", "version"=>"Submit Now! ", "project_id"=>"51"}
Project Load (0.3ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? ORDER BY created_at DESC LIMIT 1 [["id", "51"]]
Completed 500 Internal Server Error in 3ms
NoMethodError (undefined method `permit' for "Submit Now! ":String):
app/controllers/versions_controller.rb:41:in `version_params'
app/controllers/versions_controller.rb:17:in `create'
I can recognize the problem in the params. You have this:
{"utf8"=>"✓",
"authenticity_token"=>"######AAAA",
"submit"=>"Submit Now! ",
"project_id"=>"51"}
You should have this:
{"utf8"=>"✓",
"authenticity_token"=>"######AAAA",
"project_id"=>"51",
"version"=>{"title"=>"Foo Bar"},
"button"=>""}
The reason this is a problem is because you do not have a version title being passed in the params, and you are trying to create a new version with the params. It instead looks for the closest thing which in this case happens to be the string "Submit Now!", but since "submit" is not permitted than strong params tosses it out.
It looks like you are creating your form correctly, it may be an issue with bootstrap_form_for. Can you post what the input output for title looks like in html on your form?
In the meantime I have two suggestions,
First thing that may solve the problem, is to change f.submit to f.button.
f.button will still create a submit button, but it allows you to name is in the way that you are trying to.
Also in the controller, you don't need to save after you call create. create will actually store it in the database, so you are saving it twice. You should either call new instead of create
#version = #project.versions.new(version_params)
if #version.save
of check if new record
#version = #project.versions.create(version_params)
unless #version.new_record?