Form data not being sent in parameters via POST - ruby-on-rails

When I submit the form, the data is not being sent in the post and set via parameters. I can't for the life of me figure out why. This form is in the plan/show action, so that's why you see me setting the #action variable there. It is sent via JS.
routes.rb
resources :plans do
resources :actions
end
action.rb
belongs_to :plan
plan.rb
has_many :actions
plans_controller.rb
def show
#plan = current_user.plans.includes(:actions).find(params[:id])
#action = Action.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #plan }
end
end
actions_controller.rb
before_filter :get_plan
def create
#action = #plan.actions.new(params[:action])
#action.user_id = current_user.id
#action.save
end
private
def get_plan
#plan = current_user.plans.find(params[:plan_id])
end
create.js.erb in views/actions folder
$('div#actions').prepend("<%= escape_javascript(render #action) %>");
$('div#<%= dom_id(#action) %>').effect('highlight');
_form.html.erb partial
<%= form_for ([#plan, #action]), remote: true do |f| %>
<%= f.text_field :desc %>
<%= f.number_field :days %>
<%= f.submit %>
<% end %>
parameters sent via POST (missing action hash - why??)
Started POST "/plans/1/actions"
Parameters: {"utf8"=>"✓", "authenticity_token"=>"**removed**", "commit"=>"Create Action", "plan_id"=>"1"}
DB Schema
create_table "plans", :force => true do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "actions", :force => true do |t|
t.string "desc"
t.integer "plan_id"
t.integer "days"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end

Action is a reserved word. If you call it anything else (except controller, which is also reserved) then it will work.
http://guides.rubyonrails.org/action_controller_overview.html#routing-parameters
The params hash will always contain the :controller and :action keys, but you should use the methods controller_name and action_name instead to access these values.

Related

ActionController::RoutingError (No route matches [POST] "/cars/1/consumptions/new"):

I have this routing error when I add a consumption (after submit it fails) and I am stuck, What am I doing wrong?
A user can have several cars and for each of his car he wants to look after his gas consumptions.
I have three active record models
create_table "cars", force: :cascade do |t|
t.string "car_name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "consumption_searches", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "consumptions", force: :cascade do |t|
t.float "total_price"
t.float "kilometers"
t.string "shop"
t.float "liter_price"
t.float "total_liters"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "car_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
car belongs_to :users and has_many :consumptions
user has_many :cars, and has_many :consumptions through: :cars
consumption belong_to :car and belongs_to :user
My create method in consumptions_controller.rb
def create
#car = Car.find(params[:car_id])
#consumption = Consumptions.new(consumption_params)
#consumption.car = #car
if #consumption.save!
redirect_to car_consumptions_path, notice: 'consumption was successfully created.'
else
render :new
end
end
cars_controller.rb
def show
#car = Car.find(params[:id])
#search = ConsumptionSearch.new(params[:search])
#consumptions = #search.date_range
#consumptions = #consumptions.order('created_at ASC').where(car_id: #car.id)
end
views/consumptions/_form.html.erb
<%= simple_form_for car_consumptions_path do |f| %>
...
<% end %>
routes.rb
Rails.application.routes.draw do
devise_for :users
root to: "cars#index"
resources :cars do
resources :consumptions
end
end
rails routes | grep consumption
car_consumptions GET /cars/:car_id/consumptions(.:format) consumptions#index
POST /cars/:car_id/consumptions(.:format) consumptions#create
new_car_consumption GET /cars/:car_id/consumptions/new(.:format) consumptions#new
edit_car_consumption GET /cars/:car_id/consumptions/:id/edit(.:format) consumptions#edit
car_consumption GET /cars/:car_id/consumptions/:id(.:format) consumptions#show
PATCH /cars/:car_id/consumptions/:id(.:format) consumptions#update
PUT /cars/:car_id/consumptions/:id(.:format) consumptions#update
DELETE /cars/:car_id/consumptions/:id(.:format) consumptions#destroy
As requested
EDIT
here is what I have in the HTML if it can help:
<form novalidate="novalidate" class="simple_form /cars/1/consumptions" action="/cars/1/consumptions/new" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="0nwq/pQSXCU2ptBjbewTCBffPLpZZUPAj6/HPQTGtYd8cHz9zv8R/C/JYnXPDpKw5o3/vGlVtav2Sa2nSvgOQdQ==">
Lets start with the controller
# GET /cars/:car_id/consumptions/new
def new
#car = Car.find(params[:car_id])
#consumption = #car.consumptions.new
end
# POST /cars/:car_id/consumptions
def create
#car = Car.find(params[:car_id])
#consumption = #car.consumptions.new(consumption_params)
# `.save!` will raise an exception and blow up if the record is invalid.
# Not good.
if #consumption.save
redirect_to car_consumptions_path(#car), notice: 'consumption was successfully created.'
else
render :new
end
end
Note the redirect:
# consumptions#index
redirect_to car_consumptions_path(#car), notice: 'consumption was successfully created.'
Since this is a nested route you need to provide the car_id segment.
You could also redirect to:
# consumptions#show
redirect_to [#car, #consumption], notice: 'consumption was successfully created.'
# or to cars#show
redirect_to #car, notice: 'consumption was successfully created.'
When using simple_form_for you pass it model instances that it binds the form to. When creating forms for nested routes you should pass an array:
<%= simple_form_for([#car, #consumption]) do |f| %>
<% end %>
This uses the polymorphic route helpers to find the correct path. You can use this same signature for link_to, redirect_to, url_for and path_for.
When declaring nested routes you should consider using the shallow option. It will only nest the collection routes (new, create, index) and not the member routes.
Try this:
<%= form_for [#cars, #consumptions] do |form| %>
...
<% end %>
or
<%= form_with(model: [ #cars, #consumptions ]) do |form| %>
*** Update:
resources :cars, shallow: true do
resources :consumptions
end
Into form:
<% = simple_form_for [#car, #consumption] do |f| %>
You are not showing your new action, but I assume you are setting a #car and a #consumption = #car.consumptions.build variables.
Try with this:
simple_form_for #consumption, url: url_for(controller: :consumptions, action: :create, car_id: #car.id) do |f|
It should work with simple_form_for [#car, #consumption] do |f| but you said "it doesn't work" which is too ambiguous (how does that not work? same error? new error? you should be more clear when responding to answers)
car_consumptions_path != car_consumption_path
I don't see any "car_consumptions" in your routes.

Rails 5: increment value to existing array and keep old values

I'm trying to increment new values to an array but the old values get deleted. As you can see in the following, I had one image there and now its NULL, but the new image is there.
SQL (1.5ms) UPDATE "attachments" SET "media_files" = $1, "updated_at" = $2 WHERE "attachments"."id" = $3 [["media_files", "{NULL,image4.jpg}"], ["updated_at", "2018-10-25 09:12:05.564281"], ["id", 11]]
I'm using the carrierwave gem and this is the method I have inside the controller in order to keep the existing values and increment the new ones:
def create
files = #attachment.media_files # copy the old images
files += params[:item][:media_files] # add new file to the files
#attachment.assign_attributes(:media_files => files) # assign back
if #attachment.save
flash[:notice] = "Media files where successfully uploaded"
redirect_back fallback_location: root_path
else
flash[:alert] = "Failed to upload media files"
redirect_back fallback_location: root_path
end
end
And the form is:
<%= form_for #item, url: create_image_path(#attachment), method: :post , :html => {:id => "form"} do |f| %>
<%= f.file_field :media_files, multiple: true %>
<%= f.submit 'Add' %>
<% end %>
Models associations:
class Item < ApplicationRecord
has_many :attachments, dependent: :destroy
accepts_nested_attributes_for :attachments, allow_destroy: true
end
class Attachment < ApplicationRecord
belongs_to :item
mount_uploaders :media_files, AttachmentUploader
validates_presence_of :media_files
end
The schema for the two models:
create_table "attachments", force: :cascade do |t|
t.integer "item_id"
t.integer "account_id"
t.string "media_files", default: [], array: true
t.string "content_type"
t.boolean "success"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.string "title"
t.string "description"
t.integer "category_id"
t.integer "account_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The route for the create method:
post "item/:id/uploads/media_files/:id"=> "attachments#create", :as => :create_image
Any idea what I might be missing here?
You can go with your own code the modification need to done is: -
def create
exitsting_files = #attachment.media_files # copy the old images
new_file = params[:item][:media_files] # new file to the files
new_attachment = Aattachment.new(:media_files => new_file, id: #item.id) #New attachment submitted by form
if new_attachment.save
#push back your exitsting_files along with new one
#attachment.media_files.push(exitsting_files)
#attachment.save
flash[:notice] = "Media files where successfully uploaded"
redirect_back fallback_location: root_path
else
flash[:alert] = "Failed to upload media files"
redirect_back fallback_location: root_path
end
end
However this should be done with nested_atrributes_for concept
<%= form_for #item, url: create_image_path(#attachment), method: :post , :html => {:id => "form"} do |f| %>
<%= f.fields_for : attachments do |ff| %>
<%= ff.file_field :media_files, multiple: true %>
<%end%>
<%= f.submit 'Add' %>
<% end %>
And so on... you can get lots of example for nested form

Rails 4.2: Unknown Attribute or Server Error in Log

I have a form with a select_tag and options_from_collection_for_select that I can't seem to get to pass. In the view, when the upload id is set to uploadzip_id I get a 302 redirect and when it's set to uploadzip_ids, I get a Unknown Attribute error.
I'm a bit confused as I have my relationship set up along with the foreign key. I do have another model with checkboxes called Uploadpdf that works fine.
Here is the set up..
class Campaign < ActiveRecord::Base
has_one :uploadzip
end
class Uploadzip < ActiveRecord::Base
belongs_to :campaign
end
db/schema.rb
create_table "campaigns", force: :cascade do |t|
t.string "name"
t.text "comment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
create_table "uploadzips", force: :cascade do |t|
t.string "file_name"
t.string "file_type"
t.datetime "date"
t.integer "size"
t.integer "pages"
t.string "file_ident"
t.string "md5"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "campaign_id"
end
add_foreign_key "uploadzips", "campaigns"
app/controllers/campaign_controller.rb
class CampaignsController < ApplicationController
def index
#campaigns = Campaign.all.order("created_at DESC")
end
def new
#campaign = Campaign.new
end
def create
#campaign = Campaign.new(campaign_params)
if #campaign.save
flash[:success] = "Campaign Successfully Launched!"
redirect_to #campaign
else
flash[:error] = "There was a problem launching your Campaign."
redirect_to new_campaign_path
end
end
.....
private
def campaign_params
params.require(:campaign).permit(:name, :comment, :uploadzip_ids, uploadpdf_ids: [])
end
end
views/campaigns/_form.rb
<%= form_for #campaign, url: {action: "create"} do |f| %>
.....some typical fields..
<%= f.label :data_file, class: "right-label" %>
<%= select_tag campaign[uploadzip_ids],
options_from_collection_for_select(
Uploadzip.all, :id, :file_name
), { include_blank: "Include a Zip File" } %>
.....some more typical fields
<% end %>
Update
I have changed the code to better reflect the foreign key as suggested. Creating a campaign is now successful but it's not associating with the chosen uploadzip Zip file selected. When calling #campaign.uploadzip, it returns nil.
Here is the updated code:
<%= select_tag "uploadzip[campaign_id]",
options_from_collection_for_select(
Uploadzip.all, :id, :file_name
), { include_blank: "Include a Zip File" } %>
I also changed the controller params.require to..
def campaign_params
params.require(:campaign).permit(:name, :comment, :campaign_id, uploadpdf_ids: [])
end
As per your association set-up,the foreign_key should be campaign_id not uploadzip_id. You should either change your associations or foreign_key according to your use-case.
And also I recommend you to follow these Guides to know more about associations.
The 302 redirect may not be a bad thing, since you're doing a redirect_to new_campaign_path. Are the records created correctly when you use uploadzip_id in both the view and controller params.permit section?
Member of a FaceBook group helped me figure it out by adding a little
extra logic in the controller..
if #campaign.save
zip = Uploadzip.find(params[:uploadzip_id])
zip.campaign = #campaign
zip.save
flash[:success] = "Campaign Successfully Launched!"
redirect_to #campaign
else
flash[:error] = "There was a problem launching your Campaign."
redirect_to new_campaign_path
end
..which was met with changing the select_tag's name.
<%= select_tag :uploadzip_id,
options_from_collection_for_select(
Uploadzip.all, :id, :file_name
), { include_blank: "Include a Zip File" } %>

Instance of Rails model only creatable through console

I've been following the tutorial on creating a Rails blog (http://www.roberthuberdeau.com/articles/4-How-to-create-a-blog-in-Ruby-on-Rails-3) and have basically got all the way to the end.
However, after all the migrations I'm now struggling. Whenever I complete the form I previously used to create articles, I can't see them on the index page. I've dug around and believe the root of the error is that I'm not saving any articles when I press 'create article'.
To test this, I created an article using the console and this is appearing as it should so I think the problem lies somewhere between the form that creates articles and the controller (though am happy to be corrected on this).
Whenever I try the following appears in the logs:
Started POST "/articles" for 127.0.0.1 at 2013-04-01 21:12:58 +0100
Processing by ArticlesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XLeHm+4Tgd6n9vt4RxAQ5YVTbWTi+UnqkmBso9Iuo+4=", "article"=>{"title"=>"I rule", "body"=>"Change teams.", "tag_names"=>"kill", "published"=>"1"}, "commit"=>"Create Article"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles_users"."user_id" = 1 AND "roles"."name" = 'Admin' LIMIT 1
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles_users"."user_id" = 1 AND "roles"."name" = 'Moderator' LIMIT 1
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles_users"."user_id" = 1 AND "roles"."name" = 'Member' LIMIT 1
Redirected to http://localhost:3000/
Completed 302 Found in 5ms (ActiveRecord: 0.5ms)
With the database schema:
ActiveRecord::Schema.define(:version => 20130401171646) do
create_table "articles", :force => true do |t|
t.string "title"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id", :null => false
t.boolean "published", :default => false
end
create_table "comments", :force => true do |t|
t.integer "article_id"
t.string "name"
t.string "email"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "roles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "roles_users", :id => false, :force => true do |t|
t.integer "role_id"
t.integer "user_id"
end
create_table "taggings", :force => true do |t|
t.integer "article_id"
t.integer "tag_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "tags", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
Articles controller:
class ArticlesController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show]
# GET /articles
# GET /articles.xml
def index
#articles = Article.published.page(params[:page]).per(5).ordered
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #articles }
end
end
# GET /articles/1
# GET /articles/1.xml
def show
#article = Article.find(params[:id])
#comment = Comment.new(:article=>#article)
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #article }
end
end
# GET /articles/new
# GET /articles/new.xml
def new
#article = Article.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #article }
end
end
# GET /articles/1/edit
def edit
#article = Article.find(params[:id])
authorize! :edit, #article
end
# POST /articles
# POST /articles.xml
def create
authorize! :create, #article
#article = Article.new(params[:article])
#article.user_id = current_user.id
respond_to do |format|
if #article.save
format.html { redirect_to(#article, :notice => 'Article was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "new" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
# PUT /articles/1
# PUT /articles/1.xml
def update
#article = Article.find(params[:id])
authorize! :update, #article
respond_to do |format|
if #article.update_attributes(params[:article])
format.html { redirect_to(#article, :notice => 'Article was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.xml
def destroy
#article = Article.find(params[:id])
authorize! :destroy, #article
#article.destroy
respond_to do |format|
format.html { redirect_to(articles_url) }
format.xml { head :ok }
end
end
end
Articles model:
class Article < ActiveRecord::Base
attr_accessible :body, :title, :tag_names
has_many :comments, :dependent => :destroy
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
validates_presence_of :title, :body
validates_uniqueness_of :title
attr_writer :tag_names
after_save :assign_tags
validates_numericality_of :user_id
belongs_to :user
scope :published, lambda {{:conditions => ['published = ?', true]}}
scope :ordered, lambda {{:order => "Created_at DESC" }}
def tag_names
#tag_names || tags.map(&:name).join(' ')
end
private
def assign_tags
if #tag_names
self.tags = #tag_names.split(/\,/).map do |name|
Tag.find_or_create_by_name(name)
end
end
end
end
And the form partial used to create the article:
<%= form_for(#article) do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="field">
<%= f.label :tag_names, "Tags" %>
<%= f.text_field :tag_names %>
</div>
<div class="field">
<%= check_box("article", "published" ) %>
<%= "Publish article" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Any help you can give me on this would be greatly appreciated.
By request:
Ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :Admin
can :manage, :all
can :publish, Article
elsif user.role? :Moderator
can :read, [Article, Comment]
can [:edit, :update], Comment
elsif user.role? :Member
can :read, :all
can :create, [Article, Comment]
can [:edit, :update], Comment
end
end
end
p.s. the only other error I can see (and I don't know if it's relevant or a different issue entirely) is that when trying to view an article (show.html.erb) I receive the following error:
Processing by ArticlesController#show as HTML
Parameters: {"id"=>"1"}
Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT 1 [["id", "1"]]
Completed 500 Internal Server Error in 44ms
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: article):
app/controllers/articles_controller.rb:18:in `new'
app/controllers/articles_controller.rb:18:in `show'
I'm guessing there's a problem with the authorize! :create, #article line in the ArticleController.create. At the point that that executes, #article isn't created yet.
Judging by the CanCan source, I think the following might do what you want:
def create
authorize! :create, Article
#article = Article.new(params[:article])
#article.user_id = current_user.id
...
The article is not being created because of this.
authorize! :create, #article
You will have to show us your ability model, ability.rb.
You might also want to try the obvious. bundle install and restart the server.

Filling user_id attribute of Reply model (attribute that isn't attr_accesible)

I have three models: User, Post and, Reply. An user has many posts and comments. A post had many replies and belongs to an user, and a reply belongs to a post and an user.
routes.rb:
resources :posts do
resources :replies
end
schema.rb:
create_table "posts", :force => true do |t|
t.text "content", :limit => 255
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "title"
end
create_table "replies", :force => true do |t|
t.text "content"
t.integer "post_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
This is how I'm creating comments:
comments_controller.rb:
def create
#post = Post.find(params[:post_id])
#reply = #post.replies.build(params[:reply])
if #reply.save!
flash[:success] = "reply created!"
redirect_to post_path(#post)
else
redirect_to post_path(#post)
end
end
replies/_form.html.erb:
<%= form_for([#post, #post.replies.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
After submitting the form I get this error:
Validation failed: User can't be blank
I assume its because the reply's attribute user_id is empty:
reply.rb
validates :user_id, presence: true
I'm not sure how to fill that attribute. I can't just put it in Reply attr_accesible, because that would compromise the security of the app (as far as I know).
Any suggestions to solve this?
attr_acessible only affects things when you're updating/creating a record from a hash of attributes. You can always set an attribute by calling the accessor directly, so after you've built the reply,
#reply.user = current_user
Should do the trick (assuming you're using something like devise or authlogic that defined current_user for you. You could also assign to #reply.user_id directly.

Resources