Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Peristalsis
Apr 5, 2004
Move along.
I have three questions, but there's a wall o' text first.

Background:
I have to replace some existing apps that nobody likes with a Ruby on Rails web app. This app will have a back end API for other processes to send in data without going through the web pages. I'm vaguely aware of web services, and figured that would be the way to set up the API, assuming that it can be handled from the same rails server that is simultaneously handling the web app. I don't care whether I use a SOAP web service or a restful one (not entirely comfortable with the differences, but my requirements should be pretty simple database inserts and queries, so I imagine that can be done with either approach). I looked around, and it looks like the gems that let you plunk in web service functionality are old and not maintained, but that it's not supposed to be hard to do your own thing.

Current:
Working from this page, I made a GET route that can return just plain text in response to a request (which will probably be coming from curl commands in both R scripts and another Ruby script), and got a spot in my controller to render that text. I'll plan to use this to return completion codes and/or query results. I assume that setting up a post route will be similar, and that this is the way to return data to another process using the app.

My questions:
1) The requests might be quite large, involving insertion of several related and linked database rows, and will need to be parsed and processed before returning a completion code. I want to have the user pass in some XML string, or maybe a JSON construct (unless there's a better option), but I have no idea how to get that data into the controller. Should it just be a url parameter of some sort, or is there a better way to get this done?

Edit: I think I figured this one out -
code:
curl --data "xml=<input>...</input>" url
seems to do the trick, if I want to use XML input.

2) Is this the right way to go about this, or should I be looking at some more formal web service setup, even if it uses outdated code? Or some other way of setting up the API entirely?

3) Ultimately, I want to restrict use to approved people, so random weirdos can't just post data to our database for fun and profit. Is there a standard way to enforce something like that? I assume we don't just want login and password data coming through GET/POST requests.

Peristalsis fucked around with this message at 19:51 on Aug 20, 2013

Adbot
ADBOT LOVES YOU

Peristalsis
Apr 5, 2004
Move along.

Cocoa Crispies posted:

1) Put a number on "large." Kilobytes? Megabytes? Gigabytes?
By "large", I just meant it could be a page or more of XML, and probably nobody would want to put all that text as a GET param in a URL. I noted above in an edit that I figured out how to make curl populate POST params, so hopefully that will be sufficient for this.

Cocoa Crispies posted:

2) Rails is a perfectly fine web service setup; Sinatra would work too, but past some complexity point I've always found myself wishing for Rails' structure.
Well, Rails is what we're using for the app, so I'll just stick with that as long as it's legit.

Cocoa Crispies posted:

3) The easy way is to use Basic auth and HTTPS so that login and password data coming through GET & POST requests isn't unencrypted on the wire.
Thanks! I'll look into how to use that.


kayakyakr posted:

I would suggest making a standard rails app but instead of (or in addition to) html.erb files, write json.jbuilder views. Makes a pretty good web service endpoint.

You can use basic auth + https and cookies to do that or you could implement an api key/secret thing. You might look into seeing if anyone else has implemented a jsonp renderer on top of jbuilder.
It's in addition to, but I'm inclined to stick with XML for the first version, if only because one of the people writing the client code isn't a programmer. He's more likely to be familiar with XML than with JSON. I'm also not sure he's going to like shoe-horning curl commands into his R scripts, but I guess he'll have to get over it. I found info on RCurl for him, so at least he shouldn't have to shell out to the OS to make it work. Eventually, I'd like to allow both approaches (XML and JSON), probably through different Rails routes.


Thanks for the help. I feel better knowing that I'm not way off base trying to do it this way, and that just rendering non-HTML stuff is a way to return info to the calling code.

Peristalsis
Apr 5, 2004
Move along.

Cocoa Crispies posted:

What's "a page or more?" I'm going to assume it's under a few megabytes and jamming it in a POST body (that's not wrapped in form encoding) should work.

Re: HTTP Basic auth: http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic.html
Thanks.

I don't know exactly what the xml input will look like yet. We're not passing around the library of congress, but I expect that a worst case could be a text file of hundreds of lines. If I had more info, I'd give it to you. I thought I remembered that POST params are not limited in size, so that this should be a reasonable thing to pass around via HTTP. In any case, it seemed like a bad thing to put in a URL parameter.


Is this a better option than Nokogiri? I've never really liked Nokogiri, but I thought it was sort of the de facto standard for XML and HTML parsing in Ruby.


kayakyakr posted:

Don't use routing tricks, use the format parameter. Example:
/users => html
/users.json => json
/users.xml => xml

Rails knows, via respond_to/respond_with which views to render for each. Support all of the API languages in one shot and be happy. Use standard form posts and url params for bringing data in.

Thanks, I'll look into that, too. I don't think there will be an HTML version of most of the web services routes, but I'll definitely want to combine the XML and JSON in one place.


Edit: I've probably been unclear - for the most part, I'll be reading the XML, and parsing it. I might pass back query results in XML, as well, but my main problem is passing the client's XML into my code and parsing it.

Peristalsis
Apr 5, 2004
Move along.

What am I missing here? This looks like a God-awful way to construct anything. I've seen it recommended in a couple of places, but the API seems horrible, and constructing nested XML is nigh on impossible. Is there a better set of instructions than the minimal examples on the github and rubyforge sites? I guess I assumed that using this would be easier than building up XML as strings in my code, but I'm not seeing that at all.

Peristalsis
Apr 5, 2004
Move along.

Smol posted:

The good thing about libraries like Builder and Nokogiri::XML::Builder is that the structure of the code mirrors the structure of the resulting xml. For example,

Ruby code:
builder = Nokogiri::XML::Builder.new do |xml|
  xml.root {
    xml.products {
      xml.widget {
        xml.id_ "10"
        xml.name "Awesome widget"
      }
    }
  }
end

puts builder.to_xml
outputs

XML code:
<?xml version="1.0"?>
<root>
<products>
  <widget>
    <id>10</id>
    <name>Awesome widget</name>
  </widget>
</products>
</root>
The bad thing is that they're implemented via method_missing and metric poo poo-ton of closures, so performance is pretty terrible (even for ruby standards), and there's a risk of accidentally calling methods in Object (e.g. type or id).

Wait, do I have to use Nokogiri with Builder? I'm confused now - I thought they were alternate ways of doing the same things.

Peristalsis
Apr 5, 2004
Move along.

Smol posted:

They're different libraries. Nokogiri is a general purpose XML processing library which offers a Builder-like API for constructing XML documents as well. The big difference between Builder and Nokogiri::XML::Builder is that Nokogiri uses either libxml2 or a similar Java library under the hood, so it should be quite a bit faster.

Okay, sorry if I'm being dense, but let me back up. I'd like nice libraries to more easily parse and construct XML strings (and if the same gem could do both, that's even better). Someone suggested the Builder gem, but I found it difficult to understand, and nearly impossible to use. I'd like to get a better explanation of how it works, or (if it does just suck) other alternatives. Are you suggesting that Nokogiri is better?

Peristalsis fucked around with this message at 17:57 on Aug 26, 2013

Peristalsis
Apr 5, 2004
Move along.

Smol posted:

If I had to choose between the two, I'd use Nokogiri for XML generation.

As for it being impossible to understand... I wouldn't call it that. I think they're both very easy to use. But maybe it's a bit more basic thing. Have you used Ruby (or some other language where anonymous functions are considered idiomatic) a lot in the past?

I've been using Ruby for over 6 months, intermittently with Rails. I like Ruby well enough, but I've always found the documentation to be lacking, at least in organization.

For the current problem, I'll see if I can make Nokogiri do what I want, and forget about Builder for now. The main problems I was having with Builder were:
1) When trying things out in irb/Rails console, it appends an extraneous <inspect/> element - not the end of the world, but very distracting when I was trying to play with the tool to figure out what I was doing wrong.
2) I don't see a way to build up an XML string as I go along. I'm trying to model objects with a class hierarchy, and I had hoped to add elements and sub-elements to a single string/builder model as I looped over each collection. I really didn't want to have to make one huge instantiation call with every piece of information in it - keeping track of that would be far worse than building my own, simple xml generation routines in each class.
3) Getting nested elements and attributes to work without escape characters corrupting the end result was much, much harder than it needed to be.

Edit: For my background, I've been programming professionally since 1997, but mostly with more traditional tools. I've used VB and Java the most, with some work in Matlab, Perl, C/C++, AREV, and some Pascal and Mumps. There's probably one or two others that I'm not thinking of. I've hacked at some javascript to debug issues at a previous job, but never approached it systematically or anything.

Peristalsis fucked around with this message at 18:41 on Aug 26, 2013

Peristalsis
Apr 5, 2004
Move along.

Baron Dirigible posted:

Can someone please explain the difference between belongs_to: through: and has_and_belongs_to_many:? This guide says belongs_to: through: is better if I need to actually use the relationship model, whereas I don't have to with has_and_belongs_to_many -- but I need to remember to create the joining table. So, what's the difference? I'd assume if I were making a joining table I'd then be able to use the relationship model, as with belongs_to: through:, so where's the benefit of the latter choice? Is there any way for RoR to create the join table automatically?

(Edit: I think I understand now, but just to be certain: with a belongs_to: through: I need to create another model in Rails, but with has_and_belongs_to: I just need to create a join table in the migrate file / directly in mySQL?)



kayakyakr posted:

You are correct. habtm does not have an associated model while hmt does.

I was confused about this recently, too.

Both habtm and hmt need and use a join table in the database, right - it's just that one doesn't use or require a corresponding Rails model? Also, you have to create the join table in both cases, don't you? I'm assuming that they only point it out in the habtm case because it would be easier to forget it, since you don't have a model for it to remind you of its existence.

Peristalsis
Apr 5, 2004
Move along.
I'm really trying to use the built-in testing stuff for the new RoR project at work, and I can't figure out why it won't do what it's supposed to do.

I've put a dummy test in a single model class's unit test, and I just want to run the drat thing.

I've tried running this from rake, directly with ruby, with and without the -I switch (I probably have the wrong syntax for that) to capture 'test_helper', etc. The closest I come is when I get an error that a column isn't in a table. That's a true statement, but I've run a migration that deleted it, and I don't have a clue how or why the test still thinks it should be there. I'm doing development on my Windows machine, using SQLite3, if that matters. I have a Linux VM, but I'm waiting for our helpdesk to get with me to get the database set up on that appropriately, so for now, I'm stuck with Windows 7.

So, here are my questions:

1) I just want to run a single file's tests - what is the syntax for that (including the -I switch, if I need it)? I just have the default rails directory structure, with a test directory below the main app directory, and test files stubbed in by the scaffolding. I've found lots of weird and inconsistent suggestions online, none of which work for me. The best single instruction set glosses over the switch. I've been trying things on the order of "rake test <my path and file>", and I sometimes throw in a "-I <directory>" for good measure.
2) For the -I switch, some of the sources I found seem to put quotes around the path, and not leave a space after the switch but before the path - is that right?
3) What testing method does this default rails project testing use? These look like Test::Unit tests, but just running them from the command line as such doesn't work. I don't think they're Rspec, since they don't look like that syntax, but I guess I could be wrong.

Peristalsis
Apr 5, 2004
Move along.
Oh, and one more question.

I think this came up with a one-to-many relationship between two models/tables, say owners and products (one owner can own many products).

If I create a new product object, and add it to an owner like this "owner1.products << my_new_product_object", then I can see the product in the products array, the next time I execute "owner1.products". However, if I just manually set "my_new_product_object.owner_id = 1", then Rails doesn't add it to owner1.products, even though, as far as I know, the net effect should be exactly the same.

Any idea what's going on here?

Peristalsis
Apr 5, 2004
Move along.

Molten Llama posted:

Unless you're working with a plain old Ruby object, you probably need a Rails environment anyway, so don't bother with running Ruby itself or worrying about the -I argument. Start with the standard rake test, then tack on TEST=path/to/test:
code:
rake test TEST=test/models/my_fancy_active_record_model_test.rb

Thanks. If I change that to
code:
rake test TEST=test/unit/model_test.rb
the test tries to run, but I still get this weird error about the table not having a name column. Again, that's true, the name column was removed with a migration, but it's NOT for the table associated with the model I'm testing, and I don't know why or how rake/Rails thinks it needs to try to insert a name column into that table (or why it's trying to insert anything at all, for that matter):

code:
ActiveRecord::StatementInvalid: SQLite3::SQLException: table channels has no column named name: INSERT INTO "channels" ("name", 
"description", "organism", "source", "strain", "growth_medium", "growth_stage", "material_type", "replicate_type", "label", 
"pmt", "channel_number", "created_at", "updated_at", "id") VALUES ('MyString', 'MyText', 'MyString', 'MyString', 'MyString', 
'MyString', 'MyString', 'MyString', 'MyString', 'MyString', 'MyString', 1, '2013-09-09 20:01:10', '2013-09-09 20:01:10', 
980190962)

Peristalsis fucked around with this message at 21:20 on Sep 9, 2013

Peristalsis
Apr 5, 2004
Move along.

Cocoa Crispies posted:

You have some fixtures that need updating (or rather, deleting and replacing with Factory Girl).

Thanks - I didn't even know fixtures existed. I'm googling around, but not seeing any information on how to maintain them. Are migrations supposed to update fixtures automatically, or am I supposed to go change them by hand every time my data def changes? Is there a Rails command to recreate them all from scratch?

Peristalsis
Apr 5, 2004
Move along.

Peristalsis posted:

Oh, and one more question.

I think this came up with a one-to-many relationship between two models/tables, say owners and products (one owner can own many products).

If I create a new product object, and add it to an owner like this "owner1.products << my_new_product_object", then I can see the product in the products array, the next time I execute "owner1.products". However, if I just manually set "my_new_product_object.owner_id = 1", then Rails doesn't add it to owner1.products, even though, as far as I know, the net effect should be exactly the same.

Any idea what's going on here?


kayakyakr posted:

Did you reload owner1 between creating your new product object? Otherwise, it'll probably just cache the last products lookup. Are you use the product object is saving and are you sure that's the proper id?

In case anyone is interested, I think the issue here was that I hadn't saved the model objects consistently, since I was just monkeying around in rails console. If I have owner1 linked to product1 as above, but haven't saved either of them, then owner1.products returns an array with product1 in it, but product1.owner doesn't return anything. I can't reload product1, presumably because it isn't in the database yet, so I think I just have to (carefully) save things before trying to use this particular voodoo.

Peristalsis
Apr 5, 2004
Move along.
I have a weird issue. I added some code into my project from another developer, and now I'm getting a missing method error in one of the files he changed (though not directly related to his changes). The code runs fine on his box, on another developer's box, and on the test server. It's only my environment having a problem with it. I should note that the same line of code that is throwing the error now, was not throwing an error on my box previously. The error refers to a method in a gem that I've had loaded for some time.

I've re-checked out the code, I've run bundle install, etc., but I'm still getting the error. My best guess is that something corrupted the gem in question on my computer. Is there a way to force rails to re-download that gem? Does anyone have any other thoughts or suggestions?

Peristalsis
Apr 5, 2004
Move along.
Another weird issue.

We have

code:
class ApplicationController < ActionController::Base
  rescue_from DeviseLdapAuthenticatable::LdapException do |exception|
    render :text => exception, :status => 500
  end
  protect_from_forgery   <------
  before_filter :authenticate_user!
end
and

code:
class APIController < ApplicationController
  skip_before_filter :verify_authenticity_token  <-----
  ...
end
However, the protect_from_forgery is still being executed in the sub-class. If I comment out the protect_from_forgery line in the superclass, the subclass methods work. If I don't, they don't, despite the skip_before_filter exception. Any idea what I'm doing wrong?


Edit: This wasn't an issue until the other developer implemented logins with the devise gem. So it's possible that there's actually an issue with that, or with its interaction with LDAP or with the CSRF protection.

Peristalsis fucked around with this message at 21:29 on Oct 16, 2013

Peristalsis
Apr 5, 2004
Move along.
We have a shiny new RoR app with a web interface and a webserivce API for backend access. I want to adapt an old Ruby script (no Rails) to use that API, but it'll be a lot easier if I can use some of the model classes from the web app to do some parsing and processing.

This is a completely different app, running in a different directory (probably even on a different server). Is there a good way to import some of my ActiveRecord models from the Rails app to use in plain Ruby? I really don't want to re-write all the necessary logic.

Peristalsis
Apr 5, 2004
Move along.
I have a download action in a controller that's giving me some trouble.

The basic structure is this:

code:
if (user has selected some files on the page)
  construct a single zip file out of selected files
  send_file zipfile.path, :type => 'application/zip', :disposition => 'attachment', :filename => file_name
  zipfile.delete
else
  redirect_to calling page, with an alert that no files were selected
end
It works as is, and when the user specifies files, they get a file selection dialog, the zip file downloads from that, and the user drops back to the page with the list of files on it (apparently without refreshing).

My problem is that, in some cases after a successful download, I want to refresh that calling screen to put a list of certain files at the bottom. I tried putting a redirect_to in the first if-block, but got an error that I can only use one render or redirect per action. I figured Rails just wasn't smart enough to realize that only one of them could be called, so I tried to move the existing redirect after the if-else-end block and fiddle with the parameters, but that also gave me the same multiple render/redirect error.

So, I guess there must be an implicit render involved in the block with the send_to, but I don't know how to find, trace, or edit that. It doesn't seem to be using any actual view code, and rake routes shows me the route for getting into this download action, but I don't see anything that leads out of it to a view.

I'm sure I'm missing something simple, but I'm not sure where to go from here.

Peristalsis
Apr 5, 2004
Move along.

The Journey Fraternity posted:

send_file is a 'renderer' here.

Bummer.

Is there any way to edit or add to what it does? Or another way to force a refresh of the calling page?

Peristalsis
Apr 5, 2004
Move along.

Smol posted:

It's not really possible to know if a file download has started or succeeded in JavaScript. Your best bet is to initiate the download via hidden iframe that links to the zip download url, setting a cookie in the zip response and polling for the cookie in your JS code.

I don't think there's any JavaScript involved - this is all being done by http posts. I'm not worried at the moment about whether the download succeeds, I'm just trying to refresh the page that initiated the download after the send_file's render.

Edit:

KoRMaK posted:

I swear I had to deal with something similiar but I kind of forget how. I think it involved using a javascript response. Don't send the file out via the first controller, but instead make the browser ajax request the file in your js response and then you can run a switch in the js response to see if it should do anything else.

Ugh. This is all a bit beyond my expertise. Maybe I should just look for a way to send up a dialog or something with the file info for now.

Peristalsis fucked around with this message at 18:36 on Jan 30, 2014

Peristalsis
Apr 5, 2004
Move along.

Arachnamus posted:

If you just want to display something after a download, you'd do better by putting it into the page that kicks off the download.

If you're wanting to only display something after a *successful* download, that's not really something you can do without an awful lot of faff.

I want the former, but I don't have the information to display until the app starts processing the files to download. It's a list of files that are too large to download over the web app, and I get that list by looking at the file type of all the files selected by the user. Until the user selects the files and submits the list, I don't know which files can be downloaded.

However, I could just mark all the non-downloadable files on the page with an asterisk and footnote to begin with, to let the user know that those files will just have their network locations/paths listed in a text file instead. Maybe my boss will go for that.

If not, his last suggestion was to render a separate confirmation page that listed which files will be downloaded and which won't, and make the user submit from that form to start the actual download. I think that'll work, too, but it's a lot more hassle, and might not be much easier than just learning all this JavaScript stuff.

Thanks for the ideas!

Peristalsis
Apr 5, 2004
Move along.

Arachnamus posted:

You could also tag the files which are known to be too large using a data attribute or a CSS class, then use javascript to build the in-page list of files that won't be downloaded as the user is selecting them.


kayakyakr posted:

You can also use a redirector on the confirmation page if you don't have an absolute need to submit a post. To do this, when they hit download, you would send them to a download page and then use JS to open the download link 5 seconds later. Send the files as 'attachment' and they'll never leave the confirmation page.

If you need the post, consider instead creating a temporary download object that holds which files you need to send, so you will have something to redirect to.

Thanks for the additional ideas. I don't care about posting or not posting, I'm just trying to get a fix out for this as quickly as possible (i.e. changing as little of the code and structure as I can at this point). For the next version, we'll want something better than my footnote though (my boss went for that idea, so I'm on to the next artificially induced crisis), so I'll try to look into integrating JavaScript and whatnot. I've been able to work primarily on the back end of this app, and now that I'm getting UI stuff thrown at me, I need to figure out what the hell I'm doing with HTML, css, and JavaScript.

Peristalsis
Apr 5, 2004
Move along.
I think this will be an easy one, but I'm confused on how to use module functionality in different places of the app.

I have a Utils module in /lib/app_name_utils.rb. In several controller routines, I have logger = Utils::SingletonLogger.get_logger. Sometimes these assignments work, sometimes they don't. In particular, one tester tells me that roughly half the time he goes to one of the index pages, it crashes.

I've been doing some Googling, and I know I could use
code:
require app_name_utils.rb
and then
code:
include Utils
in every class where I use them, but I thought there was a way just to specify the source module when using it (and my original usage seems to work about half the time, I guess).
I'm also not clear if I have to load/require the module everywhere I use it, or just in one central place (for now, I've added config.autoload_once_paths += %W(#{config.root}/lib) to application.rb).

And I found a statement online that claimed that the name of the file in which the module resides should match the name of the module, which I haven't done. Is that critical?

Peristalsis fucked around with this message at 19:49 on Feb 4, 2014

Peristalsis
Apr 5, 2004
Move along.

Alas, we aren't using Rails 4, and I don't want to restructure this code that was supposed to go out two months ago any more than necessary.

Edit:
Let me streamline my questions.
1) Is it enough for the application just to require/load the file somewhere before its modules are included, or does it have to be loaded in every file in which it is used?
2) Once loaded, does its module have to be included in every file where it will be used, or is there some global include list?
3) Is the name of the file relative to the name of the module important?
4) Is there a way to access the module's code without including it? (E.g., using ModuleName::MethodName seems to work some of the time in test, and all the time in DEV. I must have found that somewhere....)
5) If I do include the module in a file, can I still specify the module from which it came when I call it, or do I have to call it without a prefix or module specification of any sort? I'd like to keep the module name included when it's used just for clarity.

Peristalsis fucked around with this message at 22:17 on Feb 4, 2014

Peristalsis
Apr 5, 2004
Move along.
I have a set of models that all need the same validation code (just checking a common field value against a controlled vocabulary). I'd prefer not to repeat this code in every one of the models. I created a mixin module for the vocabulary itself, but I don't think the validations can be in a mixin, can they? Is my best bet to put a new superclass with that validation between ActiveRecord and my models? Or should I not be sweating a single line of repeated validation code?

Peristalsis
Apr 5, 2004
Move along.
I have a number of has_many :through relationships in the app I'm working on, and I want to keep the join tables from filling with junk. Say we have a Doctor model linked to a Patient model through an Appointment model. If I delete a patient, I naturally want to delete any appointments that patient has. I can do this using :dependent => :destroy in the models' links, like so:

code:
has_many :appointments, :dependent => :destroy
but I wonder if this is a common enough request there's a way to tell rails always to delete join rows when one of the joined rows is deleted, or if I need to specify the dependency in each side of every join model. (I know to be careful only to delete the appointment, and not the associated doctor, in the example above.)

We're using rails 3.2.1, if that matters.

Peristalsis
Apr 5, 2004
Move along.

Smol posted:

You'll want to read the "Deleting associations" section here.

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Thanks for the link - it turns out that I had read some bad info, and didn't keep reading to see it corrected. So, as I understand it:

* There is no further shortcut - I need :dependent => :destroy for each linkage.

* I can put the :dependent => :destroy on the has_many link to the join table, OR on the has_many, :through link to the other real table. Is one considered better than the other? For the previous example, that means choosing between these:

code:
class doctor
  has_many :appointments, :dependent => :destroy
  has_many :patients, :through => :appointments
end

class patient
  has_many :appointments, :dependent => :destroy
  has_many :doctors, :through => :appointments
end

class appointments
  belongs_to :doctor
  belongs_to :patient
end

code:
class doctor
  has_many :appointments
  has_many :patients, :through => :appointments, :dependent => :destroy
end

class patient
  has_many :appointments
  has_many :doctors, :through => :appointments, :dependent => :destroy
end

class appointments
  belongs_to :doctor
  belongs_to :patient
end

Peristalsis
Apr 5, 2004
Move along.
We have a Ruby on Rails app that uses Devise for logging in and out. I'm responsible for a backend XML API. Currently, users can use cURL commands to log in, update data, etc. I now need to enable an explicit logout capabitlity through the API, and I'm having trouble making it work. Every page of the UI has a logout link, and I just want to use cULR to simulate clicking that link.

The logout sends a DELETE command to /users/sign_out, with an authenticity_token parameter. I've tried doing that with cURL, but I can't make it work. I've tried attaching the login cookie, and that didn't help. Do I need to get that authenticity token into the command data? If so, how do I do that? Would it be easier to make a new controller action and route to handle the POST/DELETE/whatever in code, so the user can just specify a URL?

Peristalsis
Apr 5, 2004
Move along.

kayakyakr posted:

Disable authenticity token for xhr calls. It makes no sense.

I don't understand this response. I'm just looking for a command to log out via cURL.

The authenticity token already isn't being checked in the controller that handles the API XML inputs, but right now I'm just trying to mimic what the logout link does (i.e. it doesn't use my code, it goes through the Devise stuff).

Peristalsis fucked around with this message at 21:30 on Jul 31, 2014

Peristalsis
Apr 5, 2004
Move along.

Lexicon posted:

What's the best way to model ordering within a scoped set of records? The project I'm working on is, roughly speaking, a survey app - Question is a model, as is QuestionSet. Currently, each Question record has a position field that is unique scoped to a QuestionSet. This represents, as expected, the order of each question within the particular survey (QuestionSet).

The problem comes in reordering - if you want to make the first question the second instead - it's necessary to modify more than one Question's position field, as the changes can cascade - in some cases to as much as every other Question in the QuestionSet. This seems unnecessary - the position integers needn't be sequential - they are only necessary to denote relative ordering. I see two possible solutions:

1) Mark the positions with large, non-adjacent integers: 100,000, 200,000, etc. Then it's possible to do any reordering of any one record and only do a save on that one record.

2) Model this in an entirely different way, and don't make the position an attribute of Question (as it is logically an attribute of QuestionSet - how that particular set displays its questions).

Any thoughts?

I think using large, non-adjacent integers is kind of an ugly hack, and in theory, it will only work until you do enough re-ordering to fill up one of the gaps.

Have you considered giving each question a reference to the next question, instead of an absolute position? Then you're basically just maintaining a linked list. There may be (probably are) better ways, but I think even this is better than using huge counters.

Peristalsis
Apr 5, 2004
Move along.

Arachnamus posted:

What happens if two people reorder them at the same time? Or two people delete one?

One of the advantages of always doing a bulk update is it's self repairing when something goes wrong.

Sorry to necro this, but what do you mean? Are you basically concerned with record locking? If so, wouldn't that be an issue for any update method?

Peristalsis
Apr 5, 2004
Move along.

Arachnamus posted:

It's a concern for any update method, yeah, but especially for one which is trying to maintain a linked list. If you're doing a mass update then a user might blat another user's changes but at least they won't leave it in a totally broken and unrecoverable (from their interface) state.

Thanks, that makes sense.

Peristalsis
Apr 5, 2004
Move along.
I have a question about using AJAX in Rails.

Here's some simplified code to illustrate my problem:

In foobars_controller.rb
code:
class FoobarController < ApplicationController
  def new
    @foobar = Foobar.new
    @other_var = 123
    ...
  end
end
In foobar's _form.html.erb
code:
<script>
  $(document).ready(function() {
    $.ajax({
      url: some.route.to.function
      data: {
        other_var: ?????
        ...
      }
    })
  });
</script>

<html>
  <% @other_var is visible here, I just need to get its value into the AJAX call, above %>
  ...
</html>
What I need to know is how to get @other_var's value into the AJAX call in _form.html.erb. I know that the html in this file has access to instance variables in the controller, but I don't know how to make them accessible to the AJAX call from there.

I assumed I'd have to stuff the value of @other_var into an HTML element of some sort, then extract it with some JavaScript, but I'm not sure how to go about that. However, the only suggestion I've had so far involves chaining the ajax().done() method in conjunction with somehow getting a json document from the controller, but this doesn't really make any sense to me.

Peristalsis
Apr 5, 2004
Move along.

A MIRACLE posted:

If the value never changes, you can just insert it with <%= @my_var %> into javascript the same as HTML

Well there's 3 hours of my life I'm never getting back.

It turns out that this is an array variable (list of row id's). Is there a best way to send this through the AJAX data setting?


A MIRACLE posted:

Also use HAML, stop using ERB

That ship has sailed for this app.

Peristalsis
Apr 5, 2004
Move along.

The Milkman posted:

Yeah, Eloquent Ruby, POODR, and The RSpec Book are the three must have books. You're unlikely to grasp the majority of it the first time through but the more you expose yourself to the concepts as you work the more you'll absorb and improve.

I'm sure this is heresy or something, but is RSpec really that much better than the built in testing suite? I found a quick introduction to it in one of the books I read (Eloquent Ruby, maybe?), very poor documentation and examples online, and I just didn't see how it was fundamentally better than the unit tests and fixtures. Are there tests I can do in RSpec that I can't do with the built-in testing framework, or is it just supposed to be more slick and fashionable?

I'll admit that I find it tiresome that every Rails tool I use has something newer/shinier/better that everyone says I should be using instead (except when I shouldn't) - Pry instead of the built-in debugger, HAML instead of erb, RSpec instead of whatever the built-in tools are called, and so on. I'd rather get proficient at using a set of good tools, than constantly be in learning curves for things that are only marginally better, and possibly not as stable.

As an example, we recently updated our Ruby and Rails versions, which made the built-in debugger almost useless. So, we're using Pry now, but I get some weird behavior from it sometimes, as well as some memory errors in my testing. I don't know if Pry isn't quite ready for prime time, or I just don't know how to use it correctly. I also don't know if Pry is causing the memory errors, or if something in my code changes is doing that. So, everything slows down and gets harder just because we want to recapture the same functionality we had before upgrading.

Sorry, I'll quit ranting now.

Peristalsis fucked around with this message at 16:51 on Nov 21, 2014

Peristalsis
Apr 5, 2004
Move along.

xenilk posted:

Yeah I've been working on a project to harden my rails skills but I just like reading on it from time to time :)

I do need to practice my TDD tho!

Thanks for the recommendation, I've ordered Eloquent Ruby :)

I enjoyed Eloquent Ruby pretty well. I also liked Design Patterns In Ruby. It's more specialized, but there's still some good, generally useful stuff in there, in addition to the pattern-specific parts.


Arachnamus posted:

With any of these things nobody who isn't a complete tool will think less of you for using one over the other, be that rspec vs testunit, erb vs haml, etc etc. Use what works for you and your team.

With this and all things I've always found having a standard to work to is more important than what that standard actually is.

Somewhere deep within the bowels of my mind, I knew this. I guess I was just blowing off some steam.

Peristalsis fucked around with this message at 21:30 on Nov 21, 2014

Peristalsis
Apr 5, 2004
Move along.
Here's a quick question.

I have an object foo of type Bar with a string property called prop.

I execute the following:

code:
foo = Bar.find(1)
puts(foo.prop)
foo.prop.sub!("original", "replacement")
puts(foo.prop)
foo.save!
foo2 = Bar.find(foo.id)
puts(foo2.prop)
The output is:
original
replacement
original

If I instead execute this:

code:
foo = Bar.find(1)
puts(foo.prop)
foo.prop = foo.prop.sub("original", "replacement")
puts(foo.prop)
foo.save!
foo2 = Bar.find(foo.id)
puts(foo2.prop)
The output is:
original
replacement
replacement

So, it appears that using sub! with an object property changes the property, but the change doesn't save, whereas setting it as an explicit assignment does. Does anyone know if this is intended behavior, or if there must just be some other, subtle problem in my code making it do this?

Peristalsis
Apr 5, 2004
Move along.

Smol posted:

Model attributes that are not marked as serializable (stuff that is saved as json or yaml strings in the database, usually arrays) are only saved when they are marked to be dirty, i.e. when you use the setter methods. If you mutate the values directly, Rails doesn't know about that.


necrotic posted:

While I wouldn't recommend it for this use case, you can force an attribute to dirty by calling foo.prop_will_change!. See the API Docs for more on dirty attributes.

Awesome, thanks folks! I don't mind going through the setter, I just wanted to understand what's going on.

Peristalsis
Apr 5, 2004
Move along.
I have a file organization question.

I'm writing a data import facility for our RoR application. I want to allow for the possibility of other importers in the future, so I extracted what core code I could into a mixin module, put that module in the lib directory, included it in the new importer class, and I put that new class in app/models/importers. Rails Console can instantiate the new objects, but when I try to write unit tests, they fail, because the rake testing function won't recognize the constant "Imports". Note that this class is NOT tied to any data table, but app/models seemed like the logical place to put it (please correct me if there's a better place for this entirely).

We have some other code that does something similar, but uses subclasses of a class in the root model directory, instead of a standalone class with a mixin. Do I have to move my importer class file up into the models directory? I really like having the files organized this way, since I anticipate having a couple of more of these import classes, and I don't really want them to clutter up a main code directory with pretty similar functionality. But if I'm breaking Rails's brain, I don't want to have to fight it constantly just for the sake of my directory being pretty.

Am I missing anything obvious that would resolve this nicely?

Peristalsis
Apr 5, 2004
Move along.
Thanks for the responses. I'm somewhere between glad and annoyed that there's not a standard answer - glad because it means I'm not just an idiot for not knowing it, and annoyed because now I have to figure out what convention is going to be "right" for this particular situation. I guess I'll try a couple of things, and hope that some layout gives us both code and tests that work, and I'll decree that that's the canonical way to do it from now on. At least my overall approach (a folder of related classes that share a mixin module) didn't elicit rage and scorn. And one of the reasons I wanted to put this in a subfolder of models was to underscore the fact that it's not ActiveRecord, just a collection of classes we use. Honestly, I kind of like the idea of giving it its own directory just under app, or maybe app/misc_classes/imports, but that would undermine the other reason I put this in app/models - namely that we already have a similar, parallel structure for another one of our sets of classes, and I don't really want to refactor the other guy's code out into my new arrangement.

I think I gave the impression that the actual code doesn't work - that's not the case. The module seems to load fine and the class works with it so far - maybe 25% of the functionality is in it right now. The problem is that the unit test won't work. I'm at home so I don't have the error message handy, but I think it was some problem with recognizing "Imports" in Imports::MyImportClass.

Oh, and this app is in Rails 3.something, though we did upgrade to Ruby 2.1.1, I think.

Adbot
ADBOT LOVES YOU

Peristalsis
Apr 5, 2004
Move along.

Pollyanna posted:

Actually, that reminds me - a lot of the Rails projects I've made are just straight "models -> database schema -> CRUD ops" setups, with rarely anything much more complicated than Users and Posts. What cases are those where you would actually use non-AR backed models, modules and extensions, and other complicated stuff?

In my case, we have a system that tracks file metadata, and we want to be able to import spreadsheets of metadata for new files. We need to look at the metadata file itself, loop over each row in it, and extract metadata from each row. We also need logic to track down the files on a network drive to which each row's metadata applies. The logic for parsing this metadata file is cumbersome and irrelevant to the rest of the system (at least once the files are located and described). I don't need to record anything about the parser itself to the database. Any information about an individual run of the parser could just be written to a log file, or, at worst, stored in a "parsing_results" table.*

I guess I think of it like this: if I'm writing a substantial program to do something - one that just executes a task rather than being of enough intrinsic interest to put info about it in the database - then I consider making it a non-AR model (or "misc_class" or whatever). The parser above is definitely an object (model?) in the system, but nothing about it is of interest to our users, and nothing about it changes from one use to the next, except the results and possibly the configuration. Changing our importer to do a different kind of work is more aptly suited to having a different (sub-)class, than it is to having a different row about it in a database.

* This could change if the parser gets more complicated, and needs to be tweaked and configured for each run. At that point, one could argue that saving the configuration and results of a parsing run would at least make for a decent audit table. Even then, though, it might make more sense to have a "parser_details" table, than to pretend that the parser is some sort of fundamental data object that relates to any other data object in the app.


Edit: We also have a process that runs overnight to validate that none of the data files that our system tracks have gone missing or become corrupted. I made this a class method of our data file AR class, but it's pretty large, and may grow to check things besides data files. I probably should have made it its own, non-AR class. There aren't different instances of the validator that have different attributes that we need or want to record in a database, it's just a program that runs periodically, and sends an email and writes a note to a log if it finds any problems.

Peristalsis fucked around with this message at 21:44 on Jan 30, 2015

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply