Jacob Montgomery

Joined

34,500 Experience
33 Lessons Completed
41 Questions Solved

Activity

Here's an interesting thing I learned that I never knew before... you can't place a form inside an html table, tbody, or tr - it can exist inside td though. Check: http://stackoverflow.com/questions/5967564/form-inside-a-table

So a quick fix to your problem is to simply move the form tag outside your <table>...</table> tags.

Now a bigger issue I noticed with your project is that you're hard coding way too much stuff - for example, all your links are plain html, so instead of using <%= link_to "Some Link", some_link_path %> you're doing <a href="/some_link">Some Link</a> - you really should be using the helpers that rails provides. The same can be said for your form itself... below is what I refactored your form to. You'll need to be sure to put @cart = Cart.new inside your index action in app/controllers/products_controller.rb

<%= form_for(@cart) do |f| %>
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Description</th>
        <th>Price</th>
        <th>Show</th>
        <th>Edit</th>
        <th>Destroy</th>
        <th>Amount</th>
        <th>购买</th>
        <th colspan="5"></th>
      </tr>
    </thead>

    <tbody>
      <% @products.each do |product| %>
        <tr>
          <td><%= product.name %></td>
          <td><%= product.description %></td>
          <td><%= product.price %></td>
          <td><%= link_to 'Show', product %></td>
          <td><%= link_to 'Edit', edit_product_path(product) %></td>
          <td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>

          <%= f.hidden_field :product_id, value: product.id %>
          <% if current_user %>
          <%= f.hidden_field :user_id, value: current_user.id %>
          <% end %>

          <td><%= f.number_field :amount, min: 1, max: 100, value: 1, autofocus: true, required: true %></td>
          <td><%= f.submit "Add to Cart", class: 'btn btn-primary' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
<% end %>

Interesting... I've only seen this type of behavior caused by Turbolinks.

Is there any way you can create a github repo that reproduces the behavior so I can take a better look?

For testing purposes, just remove the = from //= require turbolinks in application.js - so it should look like this afterwards: // require turbolinks

Then just restart your server and test your page again.

That looks like it could be a turbolinks problem. If you disable turbolinks, does it work?

Hey Robert,

You'll hear this a lot, but it really is what works - I honestly just stopped looking for how-to books / videos / tutorials and just started doing. I started with simple proof of concepts like building a simple application that lets me enter some numbers in, manipulate them in the backend, then redisplay it on the front end. Then just grew the complexity from there. Google is my best friend - if I don't know how to do something, I google it - and google it - and google it until I have read over enough "stuff" to start cobbling it together and finally make it work. If I still can't answer it, I shut down and come back to it tomorrow - and 9/10 times I answer the problem within the first hour of getting back to it.

I think for me the biggest thing has been understanding just how deliberate everything is in programming. There are very few things that "just happen" and instead took quite a bit of thought and some degree of foresight to implement a particular feature. So if you look here on this page, just the reaction feature alone can be a pretty complex beast relative to how simple it's functionality is for the user. All we have to do is click the little smiley face and we're presented with a few choices to select how we want to react, click it - and boom - your reaction is recorded. However, on the backend, all the gears that get turning just to make that sequence of events possible is a pretty impressive weaving of objects. There's helper methods, controller actions, model methods, associations between models, routing, etc... just for that one simple thing!

The thing to realize is that you'll never reach a point of understanding to where you're able to say "eureka! I now know how to program!" and ride off into the sunset in your rolling office chair programming away. That's just not the way it works. There is WAY too much information to ever fit inside any one brain. Instead, what you have to learn is general concepts and from there, how to ask the right questions. So while I use arrays all the time, I hardly have the ability to learn all the methods that go along with enumerables - but I know where to lookup enumerable class methods and I have a general idea of what I'm trying to accomplish with my array - so now it's just a matter of me reading over the docs to find the method that will let me manipulate my array the way I want to for my specific use case.

As for resources, GoRails, of course, should be #1 on your list! All of Chris' series are phenomenal and will really help you gain that general understanding you need to know before you're able to start a new project. I recently found CronDose - https://www.crondose.com/ which has some pretty neat mini tutorials for specific functionality that is really great. Outside of that - Google! If you can master the question then you can master just about any problem you're going to face.

Good luck! :)

Oh sweet, I'm glad that got the gears turning again!

This reminds me, awhile back on another project I had to be explicit when giving the partial name from the controller, I wonder if this may be similar in your case? May be worth looking into...

In my controller, I had to do this to get it to render, otherwise I'd get the missing partial error:

respond_to do |format|
  format.js { render 'shared/_toggle_alert.js.erb' }
end

This was to toggle an alert box that could pop-up on any given page. I never did figure out the real reason why it had to be written as such, I just know no other method worked. Still curious as to why I had to include the underscore and extension...

I haven't used this before, so I'm just basing this off of pure observation, but are you sure your render partial is correct? Based on this => Render Tempalte if Exists in Rails their partial path is just the partial name, whereas yours is including activity_feed

So based on this idea, you could try:

<%= render partial: activity.action.parameterize.underscore, locals: {activity: activity} %>

Posted in has_many :through association woes

What kind of queries were you doing that caused problems when you removed them? I have a feeling your queries need to be fixed instead of adding the extra associations back in. I might be wrong on this though, so I'd like to see what your problems were if you don't mind posting the errors and at least one query that caused the errors.

Tasks you would do similar to projects, but instead of creating it with the Project like you do now, you have to create it with the User since the User has_many :tasks, through: :task_assignments

current_user.tasks.create!(task_params)

@project = Project.find(params[:project_id])
redirect_to @project

You need to ensure that task_params includes the project_id so it's properly associated with the project, creating it with the user object will ensure the user_id is present so you shouldn't have to worry about it.

Posted in has_many :through association woes

Yeah, countless times I've had to just shut down and come back to it later. It's crazy how you become blind to some of that stuff after staring at it all day!!

On your models, you can clean them up by removing the extra has_many like below. There's no need for the extra has_many declaration for the project_assignments.

# user.rb
has_many :projects, through: :project_assignments
has_many :tasks, through: :task_assignments
has_many :comments

# project.rb
has_many :users, through: :project_assignments
has_many :tasks, dependent: :destroy

# task.rb
has_many :users, through: :task_assignments
belongs_to :project
has_many :comments, dependent: :destroy

Up to now I really haven't ever had to mess with a through association, so doing some extra reading it looks like there is a "special" way to do it right. So in your projects controller, try this out:

@project = current_user.projects.create!(project_params)
redirect_to :back

Your tasks you should be able to rewrite the same way. Let me know how this works out for you.

Posted in has_many :through association woes

Your project create action looks weird

@project = Project.new(project_params)
@project = current_user.projects.new(project_params)
@project.save
redirect_to :back

# @project = current_user.projects.new(project_params)
# @project.update(user_id: current_user.id)

Why are you doing @project = Project.new(project_params) and then immediately overriding it with @project = current_user.projects.new(project_params) ?

You should be able to just do:

@project = Project.new(project_params)
@project.update(user_id: current_user.id)
@project.save!
redirect_to :back

I would strongly suggest you start using byebug if you're not already - place it before each of your save methods and then when you execute your commands, byebug should trigger in your console so you can now check all your variables at that moment in time and can tell if your values are what they should be. This should help you pinpoint where the problems are coming from.

Posted in Background Jobs

Hi Sascha,

Check out this tutorial: https://www.sitepoint.com/simple-background-jobs-with-sucker-punch/

That should get you going!

Ah - I'll remove my statement to avoid misleading. I remember reading some articles awhile back related to spikes in charges and ever since then I just never looked back at them.

Thanks for the clarification Mark!

Nevermind this :)

You're welcome!

And yeah, with only 3-5 then that's not a good result, you'd know it if your app needed that much ram for something special with that few users.

I can't speak on actioncable or heroku setup, I haven't done much with either of them, but I'm sure someone else will chime in soon! However, one thing I'd probably do, if it's feasible, is to disable actioncable temporarily and see if it really is linked to actioncable or not. If you check that link (disable actioncable) - just comment the lines where he says remove - should accomplish the same thing for testing purposes. Then look at your memory usage to see if it's directly related to actioncable or something else.

Really it doesn't look that bad - you're peaking at around 1.2 gigs of ram. I have apps that can easily eat up many gigs during certain batch operations, and it's fine for those scenarios.

I think what you need to determine is how many visitors you had when you hit the 1.2 gig spike, and is that acceptable use for that load? If you only had 2 visitors, then yeah, that's probably an issue - if you had a couple million - that would probably be incredible to have only reached 1.2 gigs :)

From there you can start analyzing your app. In your main controllers, do you limit your queries where viable? For example, if you just wanted to display users emails in a view then it's much more memory friendly to do

@user_emails = User.all.pluck(:email)
###
<% @user_emails.each do |email| %>
  <%= email %>
<% end %>

vs

@user_emails = User.all
###
<% @user_emails.each do |user| %>
  <%= user.email %>
<% end %>

This is because when you don't limit your return, you're loading all the information for that object into ram, instead of just the emails. So if you can imagine a table that has a lot of records and/or a lot of columns, that memory footprint can grow quick, and from just one instance!

Check out Optimizing Rails for Memory Usage - I haven't got to read it all but from what I have, it's good stuff. Should help get you headed in the right direction.

Once you've done some basic analysis, you should be able to tell pretty quick if it's really an issue with your app or just time to upgrade! :)

Ah, you can remove project_id: @project_id if you aren't associating the comment to the project directly. Looking at your models, it doesn't look like you do, so it should be safe to remove. Sorry about that, it carried over in my mind due to a project I'm currently working on that has similar associations!

You need another table that handles assignments to threads.

# project_thread_access model
# you'll need user_id and project_thread_id columns in this model
belongs_to :project_thread_accessable, :polymorphic => true

# project_thread model
has_many :project_thread_access, as: :project_thread_accessable

# user model
has_many :project_thread_access, as: :project_thread_accessable

This would let you do something like:

current_user.project_thread_access which would return a list of project_threads that user has been assigned to.

Now, you can do something like:

def show
  redirect_to root_url, alert: "Sorry, but you do not have access to this thread" unless current_user.project_thread_access.pluck(:project_thread_id).include?(params[:id])
end

*updated redirect - alert needs to be before the condition

I haven't tested this, so it may need some tweaking - but you should get the idea

I think you have a few calls that really aren't necessary here:

# comments_controller
@project_id = params[:project_id]
@task_id = params[:task_id]

comment = Comment.new(comment_params)
comment.update(project_id: @project_id, task_id: @task_id, user_id: current_user.id)
comment.save!

When creating an object, all that's needed is the ID's for the associations, so there's no benefit in hitting the DB to grab the project and task objects since all you're really needing them for is their ID's. You're already passing that through your params, so just use those.

There might be a slicker way, but this works:

ProjectThread.find(current_user.project_posts.pluck(:project_thread_id).uniq)

This will select all the current_users project_posts, pluck the ID's of the project_thread_id, then call uniq to ensure that if a user had multiple posts in a single thread, you won't get duplicate threads.

And just to make sure, your description of how you have your models setup doesn't sound right. They should be like this:

# user model
class User < ApplicationRecord
  has_many :project_threads, through: :project_posts
  has_many :project_posts
end

# project_thread model
class ProjectThread < ApplicationRecord
  has_many :users, through: :project_posts
  has_many :project_posts
end

# project_post model
class ProjectPost < ApplicationRecord
  belongs_to :user
  belongs_to :project_thread
end

Check: http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Yep, you're correct! That is called the ternary operator

Just be aware that short code is not an absolute goal - clarity is always better than brevity - and in this case I'd argue that the ternary method isn't clear enough since it can be hard to see the ? and : in the operator, so for the sake of my fellow programmers that come after me (and myself a few months down the road), I'd go with the long form.

logo Created with Sketch.

Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

© 2020 GoRails, LLC. All rights reserved.