Get ancestor object of un-saved object in Hobo - ruby-on-rails-3

I'm working on a Hobo app trying to tie together a few models properly.
Activity objects have many Page children. They also have many DataSet children.
Page objects have several different kinds of children. We'll talk about Widget children, but there are several types with the same issue. An instance of a Widget belongs to a Page but also has a belongs_to relationship with a DataSet. Here's the important point: the DataSet must belong to the containing Activity. So for any given #widget:
#widget.page.activity === #widget.data_set.activity
It's easy enough to enforce this constraint in the model with a validation on save. The trick is presenting, within the Widget's form, a select menu of available DataSets which only contains DataSets for the current Activity
I was able to get this working for existing objects using a tag like this:
<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
However, for a new Widget, this fails messily, because either &this or &this.page is not yet set. Even for a route which contains the page ID, like /pages/:page_id/widgets/new, I'm not really able to get an Activity to scope the list of DataSets with.
If this was proper Rails, I'd get in to the relevant controller method and make the Activity available to the view as #activity or something of the sort, but in Hobo the controllers seems to be 95% Magicâ„¢ and I don't know where to start. The knowledge of which Activity is current must be in there somewhere; how do I get it out?
This is Hobo 1.3.x on Rails 3.0.x.
ETA: The code producing the errors is in the form tag for Widget, like so:
<extend tag="form" for="Widget">
<old-form merge>
<field-list: fields="&this.field_order">
<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
</field-list>
</old-form>
</extend>
As I said above, this works for editing existing Widgets, but not new Widgets; the error is undefined method 'page' for nil:NilClass. Bryan Larsen's answer seems to suggest that &this.page should not be null.

it looks like you tried to post this question to the Hobo Users mailing list -- I got a moderation message, but it doesn't appear that your post got posted, nor can I find it to let it through. Please try reposting it, there are several helpful people on the list that don't monitor the Hobo tag here.
In Hobo 1.3, the new action doesn't support part AJAX, so there really isn't much magic. You can just replace the action with your own:
def new_for_page
#activity = Activity.find(...)
#page = Page.find(params[:page_id])
#widget = #page.widgets.new
end
There is a little bit of magic referenced above: if you're in WidgetsController, assigning to #widget will also assign to this.
But as you said, the knowledge is obviously in there somewhere, and your custom controller action shouldn't be necessary.
This statement seems wrong: However, for a new Widget, this fails messily, because either &this or &this.page is not yet set.
It looks like you're properly using owner actions. /pages/:page_id/widgets/new is the route. In widgets_controller it's the new_for_page action. In a new or new_for action, this is set to an unsaved version of the object. In your action, it should have been created with the equivalent of Page.find(params[:page]).widgets.new. In other words, both this and this.page should be populated.
I'm sure you didn't make your statement up out of thin air, so there's probably something else going on.

In the end, it turned out to be syntax. Instead of
<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
I needed
<data_set-tag: options="&DataSet.activity_is(#this.page.activity)" />
(note the #).
We actually made this into a helper method, so the final code is
<data_set-tag: options="&DataSet.activity_is(activity_for(#this))" />

Related

How to add an 'image' property to questions in SurveyJS Creator?

In our application, the surveys that we create need to support an 'easy read' format whereby an image may be attached to any question, to be displayed alongside the question text.
I can't see a way to do this directly via the SurveyJS API properties, i.e. there doesn't seem to be any standard questionImage property. It therefore looks like this would need to be implemented as a custom property.
On that basis, I need to add a custom property to all question types, which the user can populate with an image in the same way as the 'image picker' question type allows you to select images. Specifically, the use-case we want to support is to open a file browser to the user's local machine and for the selected image to be encoded as a data: URI and stored in this property. (Supporting additional image-entry methods might be useful, but is not required.)
We are in a position to control the rendering of this property for respondents, so I am not concerned about how to make use of this property, just how to get it into the editor UI. Also, whilst it would be nice to see the image in the editing interface, this is also not essential behaviour at this stage.
From a Google search, I have seen similar questions, where the answer has been to insert an Image or HTML element into the survey just before the relevant question, however this is not an appropriate solution for our use-case. Firstly, it makes the survey hard to manage (both fiddly to use and also easy to break things when moving/deleting questions). Secondly, it means that the Image is rendered before the question, whereas we need it to be rendered as part of the question element (i.e. after the question number, before the question text).
Can anyone give an example for how I can add a new question property that behaves in the manner described above?
You need to add this property to surveyjs metadata:
Survey
.Serializer
.addProperty("question", {
name: "image:file",
category: "general"
});
Here is the working sample - https://plnkr.co/edit/5wpQMdMq1vxKhWaG

Model binding fails from form on Razor Page using Tag Helpers

I have a model "behind" my page with a property that's a model of my search form. My form was working fine and then suddenly all the properties stopped binding and my Post action handler saw the search form model has having loads of nulls.
When you use Tag Helpers for a form and add input controls you can add your own name="myProperty" to each, or you can omit this and this attribute is auto-generated.
Imagine you have 10 inputs and you add a new one but forget to add a name attribute on this recent one, then the helper adds its own like "SearchForm.MyProperty".
The previous 10 end up with name="myProperty" but the last one is name="SearchForm.MyProperty".
In this situation model binding fails, presumably because these paths are mixed and the one matching SearchForm.MyProperty is more specific, making the others look like they should bind to properties on the page model.
Presumably when your supply your own names and they are all lacking the SearchForm. prefix then its smart enough to figure out to bind them all to SearchForm.
Fix could be not to supply your own name attributes to the inputs at all.
An improvement to Razor binding (to remove the surprise here) might be to always fail unless the names are prefixed accurately, though this would break existing code.

selenium Page factory handle different elements for same page for different users

I have a simple question. I 'm sure many of us might have got into the same situation. I am using page object pattern. Below are the steps i do along the navigation.
Login to my application as one type of user.
Click some link to go form page.
On form page , fills the fields and submit
Logout
On 3) the form object page shows some different input fields depending on the type of the user, which i need to interact with. So how do i deal it within the same page object. Has anybody got into the same situation and have found some decent way of doing this ?
I know it a simple automation script not a Java project where we should be using all oops concepts but still I would go with the following:
Create a parent page class containing the common WebElements and methods.
Create child classes with elements and methods specific to that customer.
In the test, pass a parameter which specifies the type of customer and call the appropriate child class.
If you don't want any of this inheritance stuff, you can also try the following.
Create a page class with elements for all types of customers.
Create generic methods which can take a parameter customerType and perform operations like if customerType==1 do these operations else do these.
Another solution which popped up in my mind, assuming that all fields for a particular customer are mandatory, is as follows.
Create a common class for all elements.
Create a generic method in the page class which follows the condition, if this element is present then enter value.
If you understand the concept of Page object model then this questions will be more clear to you. Yes, inheritance is a big factor here. I suggest you read through this to see how a real page object model should work. And, solution of #3 question is as simple as UI mapping. Something like
#FindBy(how = How.NAME, using = "q")
private WebElement searchBox;
for each elements or similar implementation.
For a complete page object you should map all the elements not depending on the users. The reason being, every time you call that class it will be instantiated and all the mapped elements as well. There is no need of dynamically load the elements If any elements are not used or hidden on the page those will be available and you will not be using them anyway

Sunspot searches for Rails' Single Table Inheritance

I have a Rails app with the Content model. The Content model has numerous STI children models, such as Announcement, Story, FAQ, etc. I need to be able to query Solr via Sunspot for each of the children independently and as a group.
This is the present implementation of Sunspot search in the Content model. It sets defaults for hidden and published, so only active Content is returned by Solr and accepts a block to allow farther search params:
def self.search_for(&blk)
search = Sunspot.new_search(Content)
search.build(&blk)
search.build do
with :hidden, false
with(:published_at).less_than Time.now
end
search.execute
search
end
This method works perfectly for Content and will return results for Content and all the children Models. I am not particular thrilled with the name of the method, search_for, but can't think of anything better.
I need to be able to search by child Model, i.e. Announcement.search_for(). I do not want to have this method pasted into the ~10 child Models, since the defaults are going to change in the near future. What I would like is have each of the children models inherit this method, but search for the child's class, not Content (e.g. Announcement would search by Sunspot.new_search(Announcement)).
Is there are way to reflect the class of a class method or does this method have to be dynamically generated at runtime to pre-define the calling class?
Pretty easy, just pass the instance type rather than Content. Change first line of the function to:
search = Sunspot.new_search(self)
Where self will hold Content if you invoke the method by Content.search_for and Announcement if invoked by Announcement.search_for. That's it!

Additional actions when NSManagedObject is deleted

I have a core data 'ShoppingList' which contains 'Item' objects. I store a display order as an attribute of each item.
I would like to update the display order of all other items in the shopping list whenever an item is deleted. The code to do this is working fine when I use it in my view controller (from where the item is deleted), but since it is really related to the business objects and not the view, it would be better placed in either ShoppingList or Item.
Ideally, I would like it incorporated into the deletion of the item. So far I have tried the following:
1) Customize the standard Core Data generated ShoppingList.RemoveItemsObject (making sure to observe KVO before.after). What's strange about this way is that the item passed is stripped of its relationships to other core data entities before it gets to my code, which I need to process display orders correctly.
2) Customize Item.didTurnIntoFault. Same applies - but even attributes of the item are gone by this stage.
One answer would be to simply define a new method on ShoppingList that does my processing and then calls the original removeItemsObject. But I would prefer to know that whenever an item is removed, from anywhere, this is taken care of. This works nicely when I customize awakeFromInsert, for example - I know that whenever an item is created certain things are setup for me. But I'm surprised there's no equivalent for deletion.
Did you try to implement prepareForDeletion? Sounds like it's exactly what you're looking for.
The doc says:
You can implement this method to perform any operations required before the object is deleted, such as custom propagation before relationships are torn down, or reconfiguration of objects using key-value observing.