Jacob Montgomery

Joined

34,500 Experience
33 Lessons Completed
41 Questions Solved

Activity

Posted in Best way to create a belongs_to object from a has_many

This may not be *correct* but I believe it does what you want. There could very well be a more railsy way or a cleaner / slicker way... but here goes:

class User < ApplicationRecord
  has_one :site
  has_one :listing
  has_many :association_groups
  has_many :listings, through: :association_groups
end

#columns: user_id
class Listing < ApplicationRecord
  belongs_to :user
  has_one :site
  has_many :association_groups
  has_many :users, through: :association_groups
end

#columns: user_id, listing_id
class Site < ApplicationRecord
  has_one :user
  has_one :listing
  has_many :association_groups
  has_many :users, through: :association_groups
end

#columns: listing_id, user_id, site_id
class AssociationGroup < ApplicationRecord
  belongs_to :listing, optional: true
  belongs_to :user, optional: true
  belongs_to :site, optional: true
end



user1 = User.create
user1_site = user1.build_site.save
user1_listing = user1.build_listing.save
user1_association_group = user1.association_groups.build(listing_id: user1.listing.id, site_id: user1.site.id).save


user2 = User.create
user2_site = user2.build_site.save
user2_listing = user2.build_listing.save
user2_association_group = user2.association_groups.build(listing_id: user2.listing.id, site_id: user2.site.id).save

# assign user1 to the listing user2 created
user2.listing.association_groups.build(user_id: user1.id).save
user2.listing.users

# assign user2 to the site user1 created
user1.site.association_groups.build(user_id: user2.id).save
user1.site.users

I had to create a new table - AssociationGroup - to handle the additional associations. You may want to come up with a more descriptive name... I'm bad at naming :)

If you're using Rails 5 - you'll have to use optional: true on the AssociationGroup table since it's now required by default

Probably the trickiest thing to remember is that when you're creating a users site or listing, you can use user.build_listing or user.build_site - but if you're assigning a user to another site (that's not initially theirs), then you have to create the association through association_groups.

Be interesting to see if anyone has any other ideas!

Posted in How do I do upserts and/or conditional saves?

Excellent! Glad you were able to get it working! :)
No problem, we all start somewhere :)

I achieved to put homedir of the restricted FTP user in my deployed app

Do you mean you physically moved the users FTP folder into your rails app folder? Or did you just create the symlink? 

If you moved it, then I don't think I'd go that route as the symlink method will give you the exact same access without the negative side effects of moving a user's home directory inside your app.

Let's say the files you're trying to access are located here:

/home/user1/uploads

And you want your app to access the zip file here:

/var/www/your_rails_app/cron/files

Then your symlink command that you'd type in the terminal (not rails console) would look like this:

ln -s /home/user1/uploads /var/www/your_rails_app/cron/files

If you haven't watched it already, Chris has a wonderful video on the Whenever gem you should check out: https://gorails.com/episodes/cron-jobs-with-whenever-gem

Posted in How do I do upserts and/or conditional saves?

Hey Morgan, 

Your first_or_create method allows you to check attributes on the found or created object, you just need to remove the post_body params and assign them later to do what you want:

@new_post = Post.where(external_id: post_body[:external_id]).first_or_create

if @new_post.mod_time.present? #update record
  # do whatever updating you want
else #it's a new record
  post['objects']['img'].each do |media|
    @new_post.images.build(
        external_id: media['external_id'],
    mod_time: media['mod_time'],
    url: media['url'],
    format: media['format']
    )
  end
  @new_post.assign_attributes(post_params)
  @new_post.save 
  # you may be able to get away with just doing @new_post.update(post_params) but I can't recall if it
  # will save your newly created association as well, so you'll want to tinker with it some.
end

This might take care of your last issue as well, but I'm not 100% sure I understand what the issue is there so play with this some and if it doesn't then post back. 

Posted in Best way to create a belongs_to object from a has_many

Hah, we sure did!

No problem at all, good luck!

Posted in Best way to create a belongs_to object from a has_many

No problem at all!

You can still set it thanks to the has_one:

class Site < ApplicationRecord
def slug_candidates
[
user.first_name,
[user.first_name, user.last_name],
[user.first_name, user.last_name, user.id],
]
end
end

Posted in Best way to create a belongs_to object from a has_many

I forgot to specifically address the friendly_id part...

Can you post your method you use for friendly_id to create the subdomain? As long as it runs the `slugginator` after save when it will have the user_id then you should be good

Posted in Best way to create a belongs_to object from a has_many

Ok cool - so it looks like you just want the button to create the association and then later you'll provide a page to enter the additional info such as the subdomain and main_domain, correct?

If so, then just this would work:

class SitesController < ActionController::Base
  
  def create
    @user = User.find(params[:user_id])
    @site = @user.build_site.save
  end

end 

There's no need to mess with site_params in this case since you're not passing any of that information to the new record yet. So just pass the user_id, find that user, then use the build_site method to create the association and then call save to commit it all to the DB.

Posted in Best way to create a belongs_to object from a has_many

Hmm, I'm not sure I follow what the problem is here..

Can you provide a specific use case that prohibits this setup from working for your needs? How are you querying for your :subdomain and :main_domain that would keep you from getting the desired result?

You could be completely correct for your use case, I'm just not tracking yet is all :)

Posted in Best way to create a belongs_to object from a has_many

Hey Morgan, 

Your associations are backwards for what you're wanting I think. Try:

class Site < ApplicationRecord
  belongs_to :user
end

class User < ApplicationRecord
  has_one :site
end

Now you can build the association like so:

user.build_site

Hey LinaeAzn,

Will the file name always be the same? If so, you could create a symbolic link to the file to your public directory... so something like:

ln -s /home/path/to/file.ftp /path/to/rails/public/

You could also designate a folder in their home directory and then just symlink that directory instead and access any files placed in that directory. Just mind your security since you are putting it in the public directory.
Hey Francisco, 

Here's a basic setup to get an ajax request to render your partial

function getMonth(data, callback) {
  $.ajax({
    url: '<%= your_action_url %>',
    type: 'GET',
    data: data,
    success: callback
  });
}

I usually make a new action in the controller to handle the request, but it's not necessary:

def dates  
  @date = params[:date] ? Date.parse(params[:date]) : Date.today
end

One thing that can be a little more convoluted is if you don't know how many iterations you need to make ahead of time. So when the page first loads, do you know how many dates you'll want to go through or does it depend on something else?

If you know ahead of time, then you can just create a loop to keep running the `getDate();` function. Since you'll probably need to pass the date as a param, you can do a slight tweak as follows:


function getDate(date, data, callback) {
  $.ajax({
    url: "<%= your_action_url %> + '?date=' + date",
    type: 'GET',
    data: data,
    success: callback
  });
}

var dates = ["01-01-2018", "01-02-2018", "01-03-2018",...]
for (var i in date) {
  getDate(date);
}

*edits: looks like the normal markdown parser isn't working? Had to use the form controls instead =(

Posted in Setup for roles and authorization

Excellent!! Glad to hear you got it working, and good to know Rolify isn't necessary for this kind of setup.

Good luck!!

Posted in What is the best way to house view logic?

Hey Mark,

I think Jacks answer is the more railsy way of doing this, so if you're worried about convention then that's probably your best bet.

However, you're already stepping outside the normal rails convention space by utilizing a view model pattern, so really your idea of making another method inside your view model probably fits better with your design.

Just my thoughts FWIW, good luck!

Posted in Setup for roles and authorization

Not that I'm aware of, I think the first time I typed it I did ProjectRole but then changed to ProjectMembership just for the sake of continuity between the article and what was being said here.

For this case, I'd say it really depends on what else you may need this table to do for you. If all it's going to do is manage the roles and absolutely nothing else, then ProjectRole is probably the most descriptive. However, if you plan on storing other info there as well, maybe activity the users activity or some preferneces that are particular to that project/membership relation, then a different name would probably be more appropriate since it's doing more than just handling roles.

Posted in Setup for roles and authorization

No worries at all, this stuff can be confusing!

It kind of depends on what your final needs are and the level of granularity you need. I'd say if you can control all foreseeable actions by a simple enum role system, then just roll with that on your ProjectMembership model and let cancancan handle all the logic from there.

Unfortunately, I don't have enough experience working with either of them to give an example of some of the nuances, my usual setup is just an enum role + action_access gem since my needs are usually pretty simple.

I'd create a dummy app and do a few quick tests of the model configuration + cancancan and see if you can hammer out a few expected situations and see how it works out for you. If you hit a snag, see if that's something that Rolify could help out with. Tinkering is my favorite part of the process! :)

Posted in Setup for roles and authorization

Hey Nick,

Welcome!!

Something you may consider is adding another table, ProjectMembership and then setup has_many :through relations between your users and projects via that table.

class User < ActiveRecord::Base
  has_many :projects, :through => :project_memberships
  has_many :project_memberships
end

This should take care of your problem of a user having various roles based on the particular project their assigned. Check out this SO for additional details: https://stackoverflow.com/questions/11600928/when-should-one-use-a-has-many-through-relation-in-rails

I don't have a ton of experience with cancancan/rolify, but based on my understanding they kind of serve different purposes so you will probably want to use them together. Cancancan is focused on authorization which you scope based on the roles you setup with rolify. So you let cancancan manage authorization logic, and let rolify manage the role logic.

Posted in How do I pass an id to a foreign controller?

Hi Mark,

Can you post your routes and the link_to you're using?

Posted in Implementing global app settings

Hi RJ,

If you want a gem solution, you can look at the rails-settings gem: https://github.com/ledermann/rails-settings

I haven't used it personally so I can't give much details, but it does look like they have a decent syntax. I generally just do as you and Andrew suggested, a single table with one row for app wide settings.

Posted in Implementing Highcharts in RoR

Hey John,

You'll have to do some playing around here, but if you take a look at this JSFiddle: http://jsfiddle.net/nanosplit/xv7vut53 I've simplified it down to the bare bones of what's needed to accomplish what you want as if it were hard coded. So now all you have to do is figure out how to make it interactive... this is where ajax comes into play.

Below is pretty much the same thing as the fiddle above, but I've swapped out the hard coded parts to make an ajax call.

foo_controller.rb

def get_updated_data
    series_name = "New Data"
    series_data = [40000, 50000, 60000, 70000, 80000, 90000, 100000, 120000]
    @chart_data = [series_name, series_data]

    respond_to do |format|
      format.json { render json: @chart_data }
    end
end
$(function () {
  chart: new Highcharts.Chart({
    chart: {
      renderTo: 'container'
    },
    series: [{
      name: 'Old Data',
      data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
    }]
  });

  $('#button').click(function () {
    var chart = $('#container').highcharts();
    var url = "/get_updated_data"

    $.ajax({
      type: "GET",
      dataType: "json",
      url: url,
      success: function(data){
        newDataName = data[0]
        newData = data[1]

        var new_series = [{
          "name": newDataName,
          "data": newData,
        }];

        for (var i = chart.series.length-1; i>=0; i--) {
          chart.series[i].remove();
        }

        for (var y = new_series.length-1; y >= 0; y--) {
          chart.addSeries(new_series[y]);
        }
      }
    });    
  });  
});
For example, I assume I draw the chart in the main HTML page, then when they filter the data I use a javascript callback to change the data?

Yes, basically what you want to do is change the button click function above into a regular function that accepts parameters which you'll then use to construct a new url which the ajax call will use to fetch your new data and then render it

function updateChart(param1, param2) {
    var chart = $('#container').highcharts();
    var url = "/get_updated_data?param1=" + param1 + "&param2=" + param2

        ... rest of the stuff above

So your callback would need to call updateChart() and pass in the params based on what the user selected - updateChart(foo, bar)

You'll want to make the params part more dynamic since you're probably not going to know ahead of time how many parameters you'll be feeding at once, but this should get you rolling.

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.