How associations are updated with Synchromesh and ReactiveRecord - react.rb

How do you get Synchromesh to update Reactive Record associations?
If you consider the following model:
# models/public/post.rb
class Post < ActiveRecord::Base
has_many :comments
end
# models/public/comments.rb
class Comment < ActiveRecord::Base
belongs_to :post
end
And a component that is rendering all Posts and Comments:
def render
ul do
Todo.all.each do |todo|
li { todo.title }
ul do
todo.things.each do |thing|
li { thing.name }
end
end
end
end
The behaviour I am seeing is that any update to a Post or Comment is correctly pushed to the client and the component renders the update correctly.
However, if a new Thing is created (for a Todo being rendered), the new record arrives as a pushed notification but the list of things is not updated dynamically. (A page refresh does render the new Thing).
I have tried adding a scope to Todo but this does not make a difference.
scope :all_with_things, -> () { joins(:things) }, [Thing]
What is the best way of getting ReactiveRecord and Synchromesh to recognise a new Thing belonging to a Todo?

I believe I worked out the answer. You need to use a scope when rendering the collection.
So in the model:
# models/public/comments.rb
class Comment < ActiveRecord::Base
belongs_to :post
scope :for_post, -> (post_id) { where(post_id: post_id) }
end
And then when rendering the collection:
Todo.all.each do |todo|
li { todo.title }
ul do
Comment.for_post(post.id).each do |comment|
li { comment.body }
end
end
end
And with that it all works.

Related

gmaps4rails select scope

I have gmaps4rails working to show all locations. But, I would like to show a map with workorders using their locations. Workorder belongs_to location.
In the workorders controller, this will display all of the locations:
#json = Location.all.to_gmaps4rails
But, this won't display workorder locations:
#json = Workorder.location.all.to_gmaps4rails
This is the view code:
<%= gmaps("markers" => {"data" => #json, "options" => {"list_container" => "markers_list"} }) %>
<strong><ul id="markers_list"> </ul></strong>
belongs_to specifies a one-to-one association with another class (It returns only one entry).
to_gmaps4rails is a method from Enumerable (it expects to be called on an Array).
Also, you can't call the relation directly from the class (it's not a class method, it's an instance method):
Workorder.location.all.to_gmaps4rails
should be:
a_work_order = WOrkorder.first
a_work_order.location
and to use it with to_gmaps4rails
[a_work_order.location].to_a.compact.to_gmaps4rails
It isn't pretty, but it covers both when location is nil and when it returns something.

How to get typeahead/autocomplete text to refer to foreign id in Rails?

So I have been working on getting this Twitter Bootstrap typeahead to work and right now I can get a list of all my data when I start typing it into the form, but when I submit, the values do not get passed in as IDs. Is there any way for me to pass in an id number based on the autocomplete selection?
Here's the code I'm using...
<%= f.text_field :cargo_to_load_id, :data => { provide: "typeahead", source: Cargo.order(:name).map(&:name) , items: "9" } %>
Turns out that I need to have these getter and setter methods in my model file. These will then do the work of finding the corresponding id.
def cargo_to_unload_name
cargo_to_unload(:name)
end
def cargo_to_unload_name=(name)
self.cargo_to_unload = Cargo.find_by_name(name)
end
def cargo_to_load_name
cargo_to_load(:name)
end
def cargo_to_load_name=(name)
self.cargo_to_load = Cargo.find_by_name(name)
end

detect if a form is submitted with ruby on rails?

Is there a way to detect if a form is submitted? Im trying to set a class based on a custom validation something like below example, is that possible?
.control-group{ :class => ("error" if form_is_submitted ) }
Now trying :
.control-group{ :class => ("error" if params[:user][:profile_attributes][:gender] == nil) }
This fails if the form is not submitted because then the params are nill and throws an error
If your form data is submitted through fields with name attributes like user[profile_attributes][gender] (all having the user prefix), you can check if the :user exists in params.
... if params.include?(:user)
If for some reason (like coming from the route) params[:user] is already going to have a value even for GET requests, you can look for a specific form field having a value. For example, you could add a hidden field
<%= f.hidden_field :some_field, :value => true %>
and check for it in your condition
... if params[:user].include?(:some_field)
You can alternatively check if the request is via the POST method
... if request.post?
This works for other methods as well, like request.put? for an update method.

Duplicating a record in Rails 3

I have a prescription model in my Rails 3 application. I am trying to work out the best method of allowing records to be duplicated, but allowing the user to "review" the duplicate before it's saved.
I have read a number of questions/answers on SO (such as this one) which explain how to duplicate/clone the record and then save it - but none which explain how to show the form before save.
Reading the Rails API is appears the clone method is available.
Reading other questions and answers shows that is can be done but there is no example code apart from:
new_record = old_record.dup
The controller code I am currently working with is as follows (the model doesn't have any relationships):
# POST /prescriptions
# POST /prescriptions.json
def create
#prescription = Prescription.new(params[:prescription])
#prescription.localip = request.env['REMOTE_ADDR']
#prescription.employee = #prescription.employee.upcase
respond_to do |format|
if #prescription.save
format.html { redirect_to #prescription, notice: 'Prescription was successfully created.' }
format.json { render json: #prescription, status: :created, location: #prescription }
else
format.html { render action: "new" }
format.json { render json: #prescription.errors, status: :unprocessable_entity }
end
end
end
I am going to be linking to this clone action from the view with:
<%= link_to "Create another like this?", clone_prescription_url(#prescription), :method => :put %>
Is it as simple as adding an action to my controller like this?
def clone
#prescription = Prescription.find(params[:id])
#prescription.dup
#prescription.save
end
Apologies if the above code is completely wrong, I'm trying to get my head around it! I've seen someone do exactly what I'm trying to achieve with the cloning - but not with the editing before save.
The user that's duplicating won't have permission to edit a record once saved. It's purely for the intial data entry.
To do this, you're going to have to create a new instance of your Prescription class. "dup" works, but you're assuming it overwrites the existing record. Only methods that end with a bang(!) tend to do that.
Your code should be:
def clone
#prescription = Prescription.find(params[:id])
#new_prescription = #prescription.dup
#new_prescription.save
end
or
def clone
#prescription = Prescription.find(params[:id]).dup
#prescription.save
end
This isn't testing for times when the :id isn't found.
If you want the clone action to allow the user to review the duplicate before it is saved (AKA created), then it is almost like the "new" action, except with filled in fields already.
So your clone method could be a modification of your new method:
def new
#prescription = Prescription.new()
end
def clone
#prescription = Prescription.find(params[:id]) # find original object
#prescription = Prescription.new(#prescription.attributes) # initialize duplicate (not saved)
render :new # render same view as "new", but with #prescription attributes already filled in
end
In the view, they can then create the object.
I was looking for logic to clone an existing record. I had to modify the logic posted by ronalchn slightly because when it tried to execute the second statement of clone I got an mass assignment error because it tried to copy id, created_at, updated_at which are not included in my attr_accessible list. This is how I modified the logic to get it to work in my application using my model:
#old_event = Event.find(params[:id]) # find original object
#event = Event.new
#event.field_1 = #old_event.field_1 (statement for each field in attar_accessible)
render :new # render same view as "new", but with #prescription attributes already filled in

Have I coded myself into a corner with this custom route?

I don't even know how to write a proper title for this. I kind of cobbled together some routing code based on a bunch of different articles, and now I'm wondering if I've painted myself into a corner.
I've got a NewsArticle model, and I want the links to look like this:
/news # List of all articles
/news/2011 # List of articles published this year
/news/2011/06 # List of articles published this month
/news/2011/06/28 # List of articles published on this day
/news/2011/06/28/my-post-title # Actual article
Ok, going against the Rails way already, but so be it.
I've got routes setup like this:
controller :news_articles, :via => [:get] do
match '/news(/:year/(/:month(/:day)))' => :index, :constraints => { :year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/ }
match '/news/:year/:month/:day/:id' => :show
end
Note there is no :as declaration. That's because when I do add something like :as => "news_archive" then I end up with news_archive_path which returns something stupid like "/news?year=2010&month=4". So, I excluded that bit and wrote my own path methods in my application helper file:
def news_archive_path(year = nil, month = nil, day = nil)
return "/news" if year.nil?
t = Time.zone.local(year.to_i, month.nil? ? nil : month.to_i, day.nil? ? nil : day.to_i)
if month.nil?
"/news/#{t.year}"
elsif day.nil?
"/news/#{t.year}/#{"%02d" % t.month}"
else
"/news/#{t.year}/#{"%02d" % t.month}/#{"%02d" % t.day}"
end
end
def news_article_path(article)
t = article.published_at.in_time_zone
"#{news_archive_path(t.year, t.month, t.day)}/#{article.friendly_id}"
end
Great, this all works in practice. But now I've run into a problem where I'm testing my controllers and I want to make sure that the right links appear on the rendered templates. (Oh yeah, I'm not keeping separate view tests but instead using render_views in my controller tests.) But the tests are failing with the error undefined methodnews_article_path' for #`.
So, have I just approached this all wrong and painted myself into a corner? Or can I get out of this by somehow including the helper methods in the controller test? Or do I just suck it up for the sake of getting the test to pass and hardcode the links as I expect them to be?
To make news_article_path available you need to do:
class MyClass
include Rails.application.routes.url_helpers
end
Now MyClass#news_article_path will be defined. You can try to include the url_helpers into your test case. I've seen that break recently with "stack level too deep" errors (it creates an infinite recursion of "super" calls in initialize). If it doesn't work, create your own view helpers class and do "MyViewHelper.new.news_article_path" etc.
It's probably not a good idea to be generating the paths by concatenating string in your path helpers. Instead, simply use the url_for() method. Eg:
def news_article_path(article, options = {})
url_for(options.merge(:controller => :articles,
:action => :show,
:id => article.id,
:year => article.year,
:month => article.month,
:day => article.day))
end
(This assumes day, month, year are added as quick methods on your model, eg:
def year
self.published_at.in_time_zone.year
end
For your tests, either include the helper methods via something along these lines: My helper methods in controller - or use the url_for method again.
...That said - as you suggested, testing views within controller tests isn't ideal. :)