Rails Tutorial partial refresh - ruby-on-rails

I went through Michael Hartl's Rails Tutorial book and I want to use Ajax for automatic feed refresh, on micropost creation and micropost deletion.
As far as I understand, I only need to specify the remote: true parameter in the form inside the correct partial and respond to js inside the appropriate method.
Nevertheless, when I try to accomplish the partial refresh with a create action I'm getting a strange NoMethodError indicating that my #feed_items is a nil object.
Started POST "/microposts" for 77.70.8.167 at 2016-06-28 10:21:32 +0000
Processing by MicropostsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"qJHp9flp+EV+cxdeF69L8eSzC1fMsjr+mi57f3u3z2Y/fJI9dl1to9t4jlrX4g2uhIP67FiwvjwL7SP2Hmc4fw==", "micropost"=>{"content"=>"dsdsds"}, "commit"=>"Post"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "dsdsds"], ["user_id", 1], ["created_at", "2016-06-28 10:21:32.797365"], ["updated_at", "2016-06-28 10:21:32.797365"]]
(11.1ms) commit transaction
###################################NilClass
Rendered shared/_feed.html.erb (7.7ms)
Rendered microposts/create.js.erb (11.5ms)
Completed 500 Internal Server Error in 43ms (ActiveRecord: 11.7ms)
NoMethodError (undefined method `any?' for nil:NilClass):
app/views/shared/_feed.html.erb:3:in `_app_views_shared__feed_html_erb___1168566426182367941_69986820092480'
app/views/microposts/create.js.erb:1:in `_app_views_microposts_create_js_erb__3336806296105309297_69986601152860'
app/controllers/microposts_controller.rb:9:in `create'
Here's my _micropost.html.erb partial:
<%= form_for(#micropost, remote: true) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
<span class="picture">
<%= f.file_field :picture, accept: 'image/jpeg, image/gif, image/png' %>
</span>
<% end %>
<script type="text/javascript">
$('#micropost_picture').bind('change', function(){
size_in_megabytes = this.files[0].size/1024/1024;
if (size_in_megabytes > 5) {
alert('Maximum file size is 5MB. Please chose a smaller file.')
}
})
</script>
Create.js.erb:
$(".ajaxreloadposts").html("<%= escape_javascript(render('shared/feed')) %>");
_feed.html.erb:
<% if #feed_items.any? %>
<ol class="microposts">
<%= render #feed_items %>
</ol>
<%= will_paginate #feed_items %>
<% end %>
Create action:
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save!
# flash[:success] = "Micropost created!"
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
else
#feed_items = []
render 'static_pages/home'
end
end
_home_logged_in.html.erb:
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="stats">
<%= render 'shared/stats' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
<div class="col-md-8">
<h3>Where are your buddies right now?</h3>
<%= render 'shared/gmaps' %>
</div>
<div class="col-md-8">
<h3>Micropost Feed</h3>
<span class="ajaxreloadposts">
<%= render 'shared/feed' %>
</span>
</div>
</div>
And finally, I guess, the relevant part of my static_pages_controller:
def home
if logged_in?
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
#gmaps_users = current_user.gmaps_feed
#hash = Gmaps4rails.build_markers(#gmaps_users) do |spot, marker|
marker.lat spot.lat
marker.lng spot.lng
marker.infowindow spot.user.name
end
if !current_user.checkin.nil?
#user_lat = current_user.checkin.lat
#user_lng = current_user.checkin.lng
end
end
end
I tried following these resources, but in vain:
AJAX to update micropost vote up/down partial only refreshes the most recent post
and
AJAX feed update on post
and
How to update feed using ajax in Rails 4.0
I might have missed something, but since I'm really new to Rails, I hope you'll be merciful.
Thanks for your time, help and cheers.

Okay, it might be a bit noobish, but I managed to fix the problem by inserting an instance variable called #feed_items inside both the create and destroy methods.
def create
#feed_items = current_user.feed.paginate(page: params[:page])
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save!
# flash[:success] = "Micropost created!"
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#micropost.destroy
#feed_items = current_user.feed.paginate(page: params[:page])
# flash[:success] = "Micropost deleted!"
respond_to do |format|
format.html { redirect_to request.referrer || root_url }
format.js
end
end
Here's the rails output from micropost creation and deletion:
Started POST "/microposts" for 77.70.8.167 at 2016-06-28 12:20:56 +0000
Processing by MicropostsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"wd7XeH4MYDINH2+PrDy8perRJ77VKTwjZ82tsHdESbNWM6yw8Tj11KgU9otscfr6iuHWBUEruOH2DvU5EpS+qg==", "micropost"=>{"content"=>"workworkwork"}, "commit"=>"Post"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "workworkwork"], ["user_id", 1], ["created_at", "2016-06-28 12:20:56.699428"], ["updated_at", "2016-06-28 12:20:56.699428"]]
(11.0ms) commit transaction
(3.5ms) SELECT COUNT(*) FROM "microposts" WHERE (user_id IN (SELECT followed_id FROM relationships
WHERE follower_id = 1)
OR user_id = 1)
Micropost Load (1.2ms) SELECT "microposts".* FROM "microposts" WHERE (user_id IN (SELECT followed_id FROM relationships
WHERE follower_id = 1)
OR user_id = 1) ORDER BY "microposts"."created_at" DESC LIMIT 30 OFFSET 0
CACHE...
Rendered microposts/_micropost.html.erb (43.1ms)
Rendered shared/_feed.html.erb (60.3ms)
Rendered microposts/create.js.erb (65.5ms)
Completed 200 OK in 99ms (Views: 76.4ms | ActiveRecord: 17.6ms)
Started DELETE "/microposts/348" for 77.70.8.167 at 2016-06-28 12:20:59 +0000
Processing by MicropostsController#destroy as JS
Parameters: {"id"=>"348"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Micropost Load (0.1ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? ORDER BY "microposts"."created_at" DESC LIMIT 1 [["user_id", 1], ["id", 348]]
(0.1ms) begin transaction
SQL (0.4ms) DELETE FROM "microposts" WHERE "microposts"."id" = ? [["id", 348]]
(9.5ms) commit transaction
(0.5ms) SELECT COUNT(*) FROM "microposts" WHERE (user_id IN (SELECT followed_id FROM relationships
WHERE follower_id = 1)
OR user_id = 1)
Micropost Load (1.3ms) SELECT "microposts".* FROM "microposts" WHERE (user_id IN (SELECT followed_id FROM relationships
WHERE follower_id = 1)
OR user_id = 1) ORDER BY "microposts"."created_at" DESC LIMIT 30 OFFSET 0
CACHE...
Rendered microposts/_micropost.html.erb (50.9ms)
Rendered shared/_feed.html.erb (65.8ms)
Rendered microposts/destroy.js.erb (71.0ms)
Completed 200 OK in 99ms (Views: 75.6ms | ActiveRecord: 18.9ms)

Related

Why can't I fetch images after uploading them with the Active Storage gem?

I am also using Devise. I update the seller and the avatar image doesn't appear on the sellers page. This has been going on a while.
This is the server output in the terminal:
Started GET "/farmers" for 127.0.0.1 at 2020-08-06 19:26:57 +0100
(0.5ms) SELECT sqlite_version(*)
Processing by UserController#farmers as HTML
Rendering user/farmers.html.erb within layouts/application
User Load (2.6ms) SELECT "users"."farm_name", "avatar", "users"."about_farm", "users"."farm_type", "users"."county" FROM "users" WHERE "users"."role" = ? [["role", 1]]
↳ app/views/user/farmers.html.erb:6
ActiveStorage::Attachment Load (2.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" IS NULL AND "active_storage_attachments"."record_type"
= ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/user/farmers.html.erb:28
CACHE ActiveStorage::Attachment Load (0.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" IS NULL AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/views/user/farmers.html.erb:28
Rendered user/farmers.html.erb within layouts/application (Duration: 848.9ms | Allocations: 13223)
[Webpacker] Everything's up-to-date. Nothing to do
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?
[["id", 18], ["LIMIT", 1]]
↳ app/views/layouts/application.html.erb:47
Rendered layouts/_search.html.erb (Duration: 1.3ms | Allocations: 173)
Completed 200 OK in 1297ms (Views: 1217.8ms | ActiveRecord: 30.9ms | Allocations: 21165)
Here is a link to the code for the view page: https://gist.github.com/Josebuendia/21ba9b9a7e6b67bf593ed44675fbb97c
And the controller that fetches the data: https://gist.github.com/Josebuendia/b22486363fdffe470b27b34daad2cc9b
user = User.last
User Load (0.8ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ? [["LIMIT", 1]]
=> #<User id: 18, email: "farmer12#gmail.com", created_at: "2020-08-05 16:47:08", updated_at: "2020-08-06 17:56:28", role: 1, farm_name: "Glen Valley Farm", farmers_picture: nil, about_farm: "My farm sells organic artisan beef and lamb. I'm l...", farm_type: "Mixed", county: "Wicklow">
irb(main):013:0> user.avatar.attached?
ActiveStorage::Attachment Load (3.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ?
AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 18], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
=> true
irb(main):014:0>
ents" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ?
AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 18], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
=> true
The weird thing is that the data is fetched correctly with the items even though that's also using the Active Storage gem!
The form elements in the items form is form.
In the other forms for the users it is f.
Though, I doubt that makes a difference.
The view page code:
<p id="notice"><%= notice %></p>
<div id="itemsContainer">
<h1>Our Farmers</h1>
<% #users.each do |user| %>
<div class="itemhols">
<%
=begin%>
<h1><%= user.email %></h1>
<%
=end%>
<!--Data to include on farmers: name, pic, about, type, county-->
<h2><%= user.farm_name %></h2>
<%
=begin%>
<p><%= image_tag user.farmers_picture if user.farmers_picture.present? %></p>
<%
=end%>
<%
=begin%>
<%= image_tag user.avatar.variant(resize: "200x200").processed if user.avatar.attached? %>
<%
=end%>
<% if user.avatar.attached? %>
<image src="<%=(url_for(user.avatar))%>" class="itemholsIm">
<% end %>
<p><%= user.about_farm %></p>
<p><%= user.farm_type %></p>
<p><%= user.county %></p>
<%
=begin%>
<%= link_to 'Show', user, :class => "button", :role => "button" %>
<%
=end%>
<%
=begin%>
<--<%= link_to 'Show', item, :class => "button", :role => "button" %>
<%
=end%>
</div>
<% end %>
</div>
And the controller that fetches the data:
class UserController < ApplicationController
def login
session[:login] = 1
session[:cart] = nil
#Changed the line below to Seller Login sucessfull! from "Admin Login sucessfull!"
flash[:notice] = "Seller Login sucessfull!"
redirect_to :controller => :items
end
def logout
session[:login] = nil
session[:cart] = nil
flash[:notice] = "You have been successfully logged out!!"
redirect_to :controller => :items
end
#iteration for farmers page
def farmers
##users = User.where(role: 1)
#users = User.select(:farm_name, :avatar, :about_farm, :farm_type, :county).where(role: 1)
end
def search
st = "%#{params[:q]}%"
#users = User.where("email like ?", st)
end
def show
end
#def farmers
# #user = User.find(params[:id])
# FIXME get the view working for the farmers page
#end
def upgrade_admin
#user.update_attribute(:adminrole, true)
redirect_to :action => :admin_users
end
def downgrade_admin
#user.update_attribute(:adminrole, false)
redirect_to :action => :admin_users
end
end
This method is most likely the culprit...although there may be other issues
def farmers
##users = User.where(role: 1)
#users = User.select(:farm_name, :avatar, :about_farm, :farm_type, :county).where(role: 1)
end
Because ActiveStorage attachments are polymorpic relationships, you need to (at the very least) include the user id in the SELECT. It also seems like, based on your wording, that it worked once but at some point stopped working. My guess is it stopped working when you commented out this line...
#users = User.where(role: 1)
I would suggest just loading the entire user to avoid future problems...
def farmers
#users = User.where(role: 1)
end
Or, add :id to the select (without :avatar)
def farmers
##users = User.where(role: 1)
#users = User.select(:id, :farm_name, :about_farm, :farm_type, :county).where(role: 1)
end
Note :avatar is not needed because it isn't actually a column in the database.

using ajax for acts_as_voteable in rails

im trying to use ajax on acts_as_votable gem so the page doesnt refresh on a vote/upvote. I've adjused the controller methods for this, and added remote true on the links. However i think the only thing left are the two .js.erb files. ive looked around on here and the ruby documentation and i cant seem to find how to do it for this instance. thanks
VM23182:1 Uncaught ReferenceError: $ is not defined
at <anonymous>:1:1
at processResponse (application-50000f29e1bf2752ae7e56dda39f10dd0f67a47aea5c3f07ed0d933f3e1a256a.js:268)
at application-50000f29e1bf2752ae7e56dda39f10dd0f67a47aea5c3f07ed0d933f3e1a256a.js:196
at XMLHttpRequest.xhr.onreadystatechange (application-50000f29e1bf2752ae7e56dda39f10dd0f67a47aea5c3f07ed0d933f3e1a256a.js:251)
`$('.unlike_post').bind('ajax:success', function(){
$(this).parent().parent().find('.vote_count').html('<%= escape_javascript #post.votes_for.size.to_s %>');
$(this).closest('.unlike_post').hide();
$(this).closest('.votes').html(' <%= link_to "Like", like_post_path(#post), remote: true, method: :get, class: "like_post" %>');
});`
Started PUT "/tweets/60/like" for 127.0.0.1 at 2018-10-02 00:06:40 +0100
Processing by TweetsController#upvote as JS
Parameters: {"id"=>"60"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ /Users/benherring/.rbenv/versions/2.4.4/lib/ruby/gems/2.4.0/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
Tweet Load (0.2ms) SELECT "tweets".* FROM "tweets" WHERE "tweets"."id" = $1 LIMIT $2 [["id", 60], ["LIMIT", 1]]
↳ app/controllers/tweets_controller.rb:57
(0.4ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."voter_id" = $3 AND "votes"."vote_scope" IS NULL AND "votes"."voter_type" = $4 [["votable_id", 60], ["votable_type", "Tweet"], ["voter_id", 3], ["voter_type", "User"]]
↳ app/controllers/tweets_controller.rb:58
ActsAsVotable::Vote Load (0.6ms) SELECT "votes".* FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."voter_id" = $3 AND "votes"."vote_scope" IS NULL AND "votes"."voter_type" = $4 ORDER BY "votes"."id" DESC LIMIT $5 [["votable_id", 60], ["votable_type", "Tweet"], ["voter_id", 3], ["voter_type", "User"], ["LIMIT", 1]]
↳ app/controllers/tweets_controller.rb:58
(0.2ms) BEGIN
↳ app/controllers/tweets_controller.rb:58
ActsAsVotable::Vote Update (0.5ms) UPDATE "votes" SET "updated_at" = $1, "vote_flag" = $2 WHERE "votes"."id" = $3 [["updated_at", "2018-10-01 23:06:40.357671"], ["vote_flag", true], ["id", 10]]
↳ app/controllers/tweets_controller.rb:58
(1.3ms) COMMIT
↳ app/controllers/tweets_controller.rb:58
Rendering tweets/vote.js.erb
(0.4ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."vote_flag" = $3 [["votable_id", 60], ["votable_type", "Tweet"], ["vote_flag", true]]
↳ app/views/tweets/_icons.html.erb:5
(0.6ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."vote_flag" = $3 [["votable_id", 60], ["votable_type", "Tweet"], ["vote_flag", false]]
↳ app/views/tweets/_icons.html.erb:9
Rendered tweets/_icons.html.erb (5.7ms)
Rendered tweets/vote.js.erb (8.7ms)
Completed 200 OK in 40ms (Views: 21.0ms | ActiveRecord: 4.7ms)
resources :tweets do
member do
put "like", to: "tweets#upvote"
put "dislike", to: "tweets#downvote"
end
<div id="tweets">
<% #tweets.each do |tweet| %>
<div class="card">
<h4 class = "username"><%= link_to tweet.user.username, user_path(tweet.user) %></h4>
<p class="tweet-content"><%= tweet.content %></p>
<p class="date"><%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %></p>
<div class="icons">
<%= link_to like_tweet_path(tweet),remote: true , method: :put do %>
<div class="upvote"><i class="fas fa-thumbs-up"></i> <%= tweet.get_upvotes.size %></div>
<% end %>
<%= link_to dislike_tweet_path(tweet), remote: true, method: :put do %>
<div><i class="fas fa-thumbs-down"></i> <%= tweet.get_downvotes.size %></div>
<% end %>
</div>
</div>
<% end %>
</div>
def upvote
#tweet = Tweet.find(params[:id])
#tweet.upvote_by current_user
respond_to do |format|
format.html {redirect_to :tweets}
format.js {render layout: false}
# redirect_to :tweets
# redirect_to :tweets
# if request.xhr?
# head :ok
# else
end
end
def downvote
#tweet = Tweet.find(params[:id])
#tweet.downvote_by current_user
respond_to do |format|
format.html {redirect_to :tweets}
format.js {render layout: false}
# redirect_to :tweets
end
end
It looks like the way you initially started on is to attach handlers to the buttons that listen for successful requests. This is a fair way to do it, but - since you're already using Rails UJS - there's a possibly "better" way.
With Rails UJS, JS files returned from a remote action are automatically executed. In my opinion, a more idiomatic Rails way to do this is as follows:
Extract out the icons into their own template:
<div id="tweets">
<% #tweets.each do |tweet| %>
<div id="tweet-<%= tweet.id %>" class="card">
<h4 class = "username"><%= link_to tweet.user.username, user_path(tweet.user) %></h4>
<p class="tweet-content"><%= tweet.content %></p>
<p class="date"><%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %></p>
<%= render 'icons', tweet: tweet %>
</div>
<% end %>
</div>
tweets/_icons.html.erb:
<div class="icons">
<%= link_to like_tweet_path(tweet),remote: true , method: :put do %>
<div class="upvote"><i class="fas fa-thumbs-up"></i> <%= tweet.get_upvotes.size %></div>
<% end %>
<%= link_to dislike_tweet_path(tweet), remote: true, method: :put do %>
<div class="downvote"><i class="fas fa-thumbs-down"></i> <%= tweet.get_downvotes.size %></div>
<% end %>
</div>
Then, in your upvote/downvote controller actions you would format.js { render 'vote' } which would live at tweets/vote.js.erb and look like:
document.querySelector('#tweet-<%= #tweet.id %> .icons').outerHTML = '<%= j render('icons', tweet: #tweet) %>';
At this point, you're now free to modify tweets/_icons.html.erb to provide extra functionality (e.g. visual feedback on votes or changing the URL of the links to undo a vote).
Old jQuery method
Keeping this "older" jQuery method for those people who encounter a similar issue and are using jQuery. Though, really, you probably don't need it.
$('#tweet-<%= #tweet.id %> .icons').replaceWith('<%= j render('icons', tweet: #tweet) %>');

Rails redirect_to happening before page even shows

I have a checkout sequence in my app like this:
Cart - The user's tax is calculated and they hit a checkout button
charges#address - There is a form to update the shipping address in the user table
charges#shipping - The user chooses a shipping method (which updates order.total in the database)
charges#new - Stripe actually makes a charge
My issue is that, for some reason, the charges#shipping (step 3 is skipped, it goes from 2 to 4) is being skipped over entirely. The information for each step is below.
Step 2 Information
The form:
<%= simple_form_for(#user, url: user_path(#user), html: { method: :put }) do |f| %>
<div class="form-inputs text-left">
<div class="form-group col-sm-6">
<%= f.label :street_address_1 %>
<%= f.text_field :street_address_1, class: "form-control" %>
</div>
<div class="form-group col-sm-6">
<%= f.label :street_address_2 %>
<%= f.text_field :street_address_2, class: "form-control" %>
</div>
<div class="form-group col-sm-6">
<%= f.label :city %>
<%= f.text_field :city, class: "form-control" %>
</div><div class="form-group col-sm-3 col-xs-6">
<%= f.label :state %>
<%= f.text_field :state, class: "form-control" %>
</div><div class="form-group col-sm-3 col-xs-6">
<%= f.label :zip %>
<%= f.text_field :zip, class: "form-control" %>
</div><div class="form-group col-sm-6">
<%= f.label :provence %>
<%= f.text_field :provence, class: "form-control" %>
</div><div class="form-group col-sm-6">
<%= f.label :country %>
<%= f.text_field :country, class: "form-control" %>
</div><div class="form-group">
<%= f.hidden_field :has_shipping, value: true %>
</div>
</div> <!-- form inputs -->
<%= f.button :submit, "Calculate Shipping" %>
<% end %>
The method in users_controller which should be sending it to the charges#shipping page, but it ends up on charges#new:
def update
#user = User.find(params[:id])
#user.update_attributes(account_update_params)
if #user.update(account_update_params)
redirect_to charges_shipping_path
else
render :back
flash[:notice] = "Something is amuck."
end
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password, :phone, :admin, :stripe_customer_id, :street_address_1, :street_address_2, :city, :state, :zip, :provence, :country, :has_shipping)
end
Here's what's happening in the server:
Started PUT "/users/1" for ::1 at 2017-05-16 10:04:10 -0700
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"R2ZDErL9UQ6nPNyYDI9FDeOp0x29t+/STWIkTKeShz2WWdO8kWu+z6V5NS/EKI6uiLcCAQBbwbsRMlhGs8v2VA==", "user"=>{"street_address_1"=>"10 Oak View Drive", "street_address_2"=>"Test", "city"=>"Aliso Viejo", "state"=>"CA", "zip"=>"92656", "provence"=>"", "country"=>"US", "has_shipping"=>"true"}, "commit"=>"Calculate Shipping", "id"=>"1"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
(0.1ms) begin transaction
(0.1ms) commit transaction
(0.0ms) begin transaction
(0.0ms) commit transaction
Redirected to http://localhost:3000/charges/shipping
Completed 302 Found in 5ms (ActiveRecord: 0.3ms)
Started GET "/charges/shipping" for ::1 at 2017-05-16 10:04:10 -0700
Processing by ChargesController#shipping as HTML
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Order Load (0.1ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT 1 [["id", 5]]
CACHE (0.0ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT 1 [["id", 5]]
(0.1ms) begin transaction
OrderItem Load (0.1ms) SELECT "order_items".* FROM "order_items" WHERE "order_items"."order_id" = ? [["order_id", 5]]
Product Load (0.0ms) SELECT "products".* FROM "products" WHERE "products"."active" = ? AND "products"."id" = ? LIMIT 1 [["active", "t"], ["id", 2]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."active" = ? AND "products"."id" = ? LIMIT 1 [["active", "t"], ["id", 1]]
(0.0ms) commit transaction
156.95
(0.0ms) begin transaction
(0.0ms) commit transaction
Redirected to http://localhost:3000/charges/new
CACHE (0.0ms) SELECT "order_items".* FROM "order_items" WHERE "order_items"."order_id" = ? [["order_id", 5]]
CACHE (0.0ms) SELECT "products".* FROM "products" WHERE "products"."active" = ? AND "products"."id" = ? LIMIT 1 [["active", true], ["id", 2]]
CACHE (0.0ms) SELECT "products".* FROM "products" WHERE "products"."active" = ? AND "products"."id" = ? LIMIT 1 [["active", true], ["id", 1]]
Completed 302 Found in 1965ms (ActiveRecord: 0.6ms)
Started GET "/charges/new" for ::1 at 2017-05-16 10:04:12 -0700
Processing by ChargesController#new as HTML
Order Load (0.1ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT 1 [["id", 5]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
CACHE (0.0ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT 1 [["id", 5]]
Rendered charges/_shipping.html.erb (2.1ms)
Rendered charges/new.html.erb within layouts/application (3.1ms)
CACHE (0.0ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT 1 [["id", 5]]
(0.1ms) SELECT COUNT(*) FROM "order_items" WHERE "order_items"."order_id" = ? [["order_id", 5]]
CACHE (0.0ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT 1 [["id", 5]]
OrderItem Load (0.1ms) SELECT "order_items".* FROM "order_items" WHERE "order_items"."order_id" = ? [["order_id", 5]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."active" = ? AND "products"."id" = ? LIMIT 1 [["active", "t"], ["id", 2]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."active" = ? AND "products"."id" = ? LIMIT 1 [["active", "t"], ["id", 1]]
Rendered layouts/_cart_text.html.erb (6.1ms)
Completed 200 OK in 82ms (Views: 80.6ms | ActiveRecord: 0.6ms)
Here's the form in step 3 (the one being skipped, though all that really matters here is that it's a form_for(#order):
<h3>Shipping Rates</h3>
<% shipping_choices = [] %>
<% #ups_rates.each do |rate| %>
<% choice = [] %>
<% choice << number_to_currency(rate[1]/100) %>
<% choice << number_to_currency(rate[1]/100).to_s + " - " + rate[0].to_s %>
<% shipping_choices << choice %>
<% end %>
<%= simple_form_for order_path(#order) do |f| %>
<div class="row">
<div class="form-inputs text-left">
<div class="form-group col-sm-6">
<%= f.collection_radio_buttons :shipping, shipping_choices, :first, :last, item_wrapper_class: :block_radio_button_collection %>
</div>
</div> <!-- form inputs -->
</div> <!-- choices row -->
<div class="row">
<%= f.button :submit, "Calculate Shipping" %>
</div>
<% end %>
And here's the order#update method:
def update
#order = current_order
if #order.update(order_params)
redirect_to charges_address_path
else
render :back
flash[:notice] = "Something is amuck."
end
end
This is a very strange problem for me. Can anyone see where I'm going wrong?
Additional Information
As requested, here is my (unfortunately long) `charges#shipping` method:
def shipping
#user = current_user
#products = current_order.order_items.all
#order = current_order
if #order.update(order_params)
new_total = #order.total + #order.shipping
#order.update_attributes(total: new_total)
redirect_to new_charge_path
else
render :back
flash[:notice] = "Something is amuck."
end
#envelope_weight = 0
#not_envelope = 0
#products.each do |thing|
if thing.product.envelope
#envelope_weight += thing.product.weight
else
#not_envelope += 1
end
end
if #not_envelope == 0
# shipping for envelope
else
packages = []
#products.each do |thing|
unless thing.product.envelope
if thing.id == 1
packages << ActiveShipping::Package.new( (thing.product.weight + #envelope_weight ) * 16,
[thing.product.box_length, thing.product.box_width, thing.product.box_depth],
units: :imperial)
else
packages << ActiveShipping::Package.new( thing.product.weight * 16,
[thing.product.box_length, thing.product.box_width, thing.product.box_depth],
units: :imperial)
end # envelope weight if else
end #unless
end ## each do
end # not envelope if/else
origin = ActiveShipping::Location.new( country: 'US', state: 'CO', city: 'Sedalia', zip: '80135')
if #user.country == 'US'
destination = ActiveShipping::Location.new( country: #user.country, state: #user.state, city: #user.city, zip: #user.zip)
else
destination = ActiveShipping::Location.new( country: #user.country, province: #user.state, city: #user.city, postal_code: #user.zip)
end # if/else for country
ups = ActiveShipping::UPS.new(login: 'lizbayardelle', password: 'UPSpassw0rd', key: '3D287D7B39D0D398')
ups_response = ups.find_rates(origin, destination, packages)
#ups_rates = ups_response.rates.sort_by(&:price).collect {|rate| [rate.service_name, rate.price]}
usps = ActiveShipping::USPS.new(login: '380LINCH6422')
usps_response = usps.find_rates(origin, destination, packages)
#usps_rates = usps_response.rates.sort_by(&:price).collect {|rate| [rate.service_name, rate.price]}
end
First you redirected from UsersController#update to ChargesController#shipping, it went into the shipping action where the condition for if #order.update(order_params) became true as order_params is nil here and hence it redirected to ChargesController#new
When you do a redirect_to in rails, it redirects as a GET request. When you submit a form, it will be POST/PUT by default(unless you change it).
You can even see in your logs, how all redirects are going in as GET.
It is not advisable to use same action for both. If you do want to use same action make sure you are adding a check for request.method=='GET' or request.method=='POST' in them.
From what I see in your shipping action code, it was written to handle form submits(POST) and not for handling GET requests via redirects.
So either handle it logically or seperate it into seperate actions, one to render the form and other to handle the form submit.
P.S. Also do not forget to add 'and return' after each redirect.
redirect_to charges_shipping_path and return

Rails object loses params value while creating it

I have Product model with some params (price, category_id, image etc.).
When creating a new product in the form partial, category is being selected via select_tag and image gets uploaded via Carrierwave, image uploader. Bad things happens when I send user to crop the uploaded image in crop.html.erb file. There user crops image, clicks submit, which uses path as update (not very sure which HTTP protocol), and gets redirected into product edit page, since product somehow lost category_id parameter. Form shows error to select a category (all other params from input_fields does not get lost).
My tries was like defining the crop method and setting category there, but no luck...
products_controller.rb:
def edit
#categories = Category.all
end
def create
#product = Product.new(product_params)
#product.category_id = params[:category_id]
#product.user_id = current_user.id
respond_to do |format|
if #product.save
if params[:product][:image].present?
format.html { render :crop }
else
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
end
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
#product.category_id = params[:category_id]
respond_to do |format|
if #product.update(product_params)
if params[:product][:image].present?
format.html { render :crop }
else
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
#products = Product.all
ActionCable.server.broadcast 'products',
html: render_to_string('store/index', layout: false)
end
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
crop.html.erb (in products folder):
<%= image_tag #product.image_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:300px; height:200px; overflow:hidden;">
<%= image_tag #product.image.url(:large), :id => "preview" %>
</div>
<%= form_for #product do |f| %>
<% %w[x y w h].each do |attribute| %>
<%= f.hidden_field "crop_#{attribute}" %>
<% end %>
<div class="actions">
<%= f.submit "Crop" %>
</div>
<% end %>
I haven't tried to set a callback that stores category_id, but I wonder would it be a good idea? Any help? Thanks!
EDIT - also adding a form partial, but it works fine - just for your curiosity:
<%= form_for(product, hmtl: { multipart: true } ) do |f| %>
...
<div class="field">
<%= f.label :category %>
<%= select_tag(:category_id, options_from_collection_for_select(Category.all, :id, :name, #product.category_id), include_blank: "Select Category") %>
</div>
UPDATE
Logs for these actions:
Started GET "/products/new" for ::1 at 2016-12-15 09:03:31 +0200
Processing by ProductsController#new as HTML
[1m[36mCart Load (0.4ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mCACHE (0.0ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mUser Load (2.0ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
Rendering products/new.html.erb within layouts/application
[1m[36mCategory Load (0.4ms)[0m [1m[34mSELECT "categories".* FROM "categories"[0m
Rendered products/_form.html.erb (6.2ms)
Rendered products/new.html.erb within layouts/application (11.2ms)
[1m[36mCACHE (0.0ms)[0m [1m[34mSELECT "categories".* FROM "categories"[0m
[1m[36mLineItem Load (0.5ms)[0m [1m[34mSELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = $1[0m [["cart_id", 5]]
Completed 200 OK in 127ms (Views: 113.2ms | ActiveRecord: 3.3ms)
Started POST "/products" for ::1 at 2016-12-15 09:03:40 +0200
Processing by ProductsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"eWZuqL6AqcN8wknjEL115ax9uBnpY4b9eP0o2xN2aPntd61YKyc4Ym1lUgjV1YrXfZbPr57HANXy7Kz5swCtlg==", "product"=>{"title"=>"kj", "description"=>"kj", "image"=>#<ActionDispatch::Http::UploadedFile:0x007fe40ba4abe0 #tempfile=#<Tempfile:/var/folders/dn/zq9x2jkd4856kwhfj5gbz2tc0000gn/T/RackMultipart20161215-3987-1adfacs.png>, #original_filename="Screen Shot 2016-12-05 at 09.14.48.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"product[image]\"; filename=\"Screen Shot 2016-12-05 at 09.14.48.png\"\r\nContent-Type: image/png\r\n">, "price"=>"98", "quantity"=>"98"}, "category_id"=>"1", "commit"=>"Create Product"}
[1m[36mCart Load (0.3ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mCACHE (0.0ms)[0m [1m[34mSELECT "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m [["id", 5], ["LIMIT", 1]]
[1m[36mUser Load (0.7ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
[1m[35m (0.3ms)[0m [1m[35mBEGIN[0m
[1m[36mCategory Load (0.3ms)[0m [1m[34mSELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
[1m[35mSQL (1.0ms)[0m [1m[32mINSERT INTO "products" ("title", "description", "price", "quantity", "created_at", "updated_at", "category_id", "user_id", "image") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"[0m [["title", "kj"], ["description", "kj"], ["price", #<BigDecimal:7fe40ccf9110,'0.98E2',9(18)>], ["quantity", 98], ["created_at", 2016-12-15 07:03:41 UTC], ["updated_at", 2016-12-15 07:03:41 UTC], ["category_id", "1"], ["user_id", 1], ["image", "Screen_Shot_2016-12-05_at_09.14.48.png"]]
[1m[35m (3.1ms)[0m [1m[35mCOMMIT[0m
Rendering products/crop.html.erb within layouts/application
Rendered products/crop.html.erb within layouts/application (3.1ms)
[1m[36mCategory Load (0.7ms)[0m [1m[34mSELECT "categories".* FROM "categories"[0m
[1m[36mLineItem Load (0.3ms)[0m [1m[34mSELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = $1[0m [["cart_id", 5]]
Completed 200 OK in 957ms (Views: 127.8ms | ActiveRecord: 6.7ms)
So I noticed that it renders products/crop.html.erb without a particular ID, so I added in my routes:
resources :products do
get 'crop', on: :member
end
And products_controller create action:
...
respond_to do |format|
if #product.save
if params[:product][:image].present?
format.html { render crop_product_path(#product) }
else
...
Still the same error, that a category must be selected.
And to note - if simply go to edit product (but not from the crop action), category sits there as supposed...
Since form only submits the parameters gathered which are defined in it, you should add a hidden field to set the category_id in crop.html view
<%= image_tag #product.image_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:300px; height:200px; overflow:hidden;">
<%= image_tag #product.image.url(:large), :id => "preview" %>
</div>
<%= form_for #product do |f| %>
<% %w[x y w h].each do |attribute| %>
<%= f.hidden_field "crop_#{attribute}" %>
<% end %>
<%= f.hidden_field :category_id %>
<div class="actions">
<%= f.submit "Crop" %>
</div>
<% end %>
Now, when you submit the form, you will receive category_id on server in params[:product][:category_id]

acts_as_votable not working when I upvote/downvote

I am trying to allow treatment to be votable with upvotes or downvotes but the methods provided by act_as_votable don't seem to be working as intended. When I try to display the sum of upvotes-downvotes it returns 0 each time, implying votes aren't registering like they should.
My treatments_controller.rb
def upvote
#treatment = Treatment.find(params[:id])
#treatment.upvote_by #current_user
render 'show'
end
def downvote
#treatment = Treatment.find(params[:id])
#treatment.downvote_by #current_user
redirect_to treatments_path
end
My treatment.rb
class Treatment < ActiveRecord::Base
acts_as_votable
has_many :review
has_one :service
def score
self.get_upvotes.size - self.get_downvotes.size
end
end
My routes.rb
resources :treatments do
member do
put "like", to: "treatments#upvote"
put "dislike", to: "treatments#downvote"
end
end
And my treatments/show.html.erb
<div class="container">
<div class="row">
<div class="col-sx-12 col-sm-12 col-md-8">
<h3><%= #treatment.name %></h3></br></br>
<h3>
<%= link_to "upvote", like_treatment_path(#treatment), method: :put %></br>
<%= link_to "downvote", dislike_treatment_path(#treatment), method: :put %></br>
<%= #treatment.score %></br> </h3>
The server log says the following
Started PUT "/treatments/1/like" for ::1 at 2015-12-09 16:22:14 +0000
Processing by TreatmentsController#upvote as HTML
Parameters: {"authenticity_token"=>"hQnqV+OZ6m/9kFnr5YH6j563DIjyKfA4K/8fH6kpFbXbJRbsHCcNYn1AX4usZmUNXPlnFpxHMwTM8ilFxcbdhQ==", "id"=>"1"}
Geokit is using the domain: localhost
Treatment Load (0.5ms) SELECT "treatments".* FROM "treatments" WHERE "treatments"."id" = ? LIMIT 1 [["id", 1]]
(0.5ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 1], ["votable_type", "Treatment"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 1], ["votable_type", "Treatment"], ["vote_flag", "f"]]
Rendered treatments/show.html.erb within layouts/application (6.5ms)
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 4]]
Completed 200 OK in 569ms (Views: 563.3ms | ActiveRecord: 1.0ms)
Thanks to the help of Kristjan I realised there was no insertion happening. I defined current_user within the upvote and downvote methods. The revised working versions look like so.
def upvote
current_user = User.find_by_id(session[:user_id])
#treatment = Treatment.find(params[:id])
#treatment.upvote_by current_user
render 'show'
end
def downvote
current_user = User.find_by_id(session[:user_id])
#treatment = Treatment.find(params[:id])
#treatment.downvote_by current_user
render 'show'
end

Resources